您的位置:首页 > 职场人生

黑马程序员——Java堆栈区别

2015-10-18 23:17 399 查看

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

一.Java 内存分类:

在Java中主要存在4块内存空间:

(1)栈内存空间 ( 2)堆内存空间 (3)静态区 (4)代码区

1、栈区(stacksegment)—由编译器自动分配释放,存放函数的参数值,局部变量的值等,
      具体方法执行结束之后,系统自动释放JVM内存资源
   2、堆区(heapsegment)—一般由程序员分配释放,存放由new创建的对象和数组,
      jvm不定时查看这个对象,如果没有引用指向这个对象就回收
   3、静态区(datasegment)—存放全局变量,静态变量和字符串常量,不释放
   4、代码区(codesegment)—存放程序中方法的二进制代码,而且是多个对象共享一个代码空间区域


二. 堆栈定义:

1.堆栈的地址:

(1)JVM(虚拟机)在启动后,会在内存较低位置建立一块区域,作为堆。并有默认的大小。当不够时,自动向下延伸。
      (2)会在内存较高位置建立一块区域,作为栈,当不够时,自动向上延伸。
      当堆和栈延伸到一起时,就会引发内存溢出错误。

    2.堆栈存放的数据: 
      (1)堆是一个运行时数据区,类的对象从中分配空间。
           这些对象通过new、newarray、anewarray和multianewarray等指令建立,
           它们不需要程序代码来显式的释放。


(2)栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。

三.堆栈例子:

1.对象的存储

int score[]=null; //只分配了栈内存

score = new int[3]; //分配了对内存三个。对内存上的这个三个数相当于人,而人可以有很多个名字,score这个栈里只是它其中一个名字。必须有new关键字,才分配了堆内存。



2.字符串在字符串池中的存储

String str1 = "abc"; //此时 “abc“这个字符串是存放到了内存的字符串池中(不是堆内存中)。

String str2 = "abc"; //因为栈的数据共享性,此刻查找字符串池,发现有abc这个字符串,那么这里就直接共享此数据

System.out.println(str1==str2); //true

3. 字符串在堆中的存储

String str1 =new String ("abc");

String str2 =new String ("abc");

System.out.println(str1==str2); // false

用new的方式是生成不同的对象。在堆中对应两个不同地址,所以两个对象==比较为false。

== 是比较地址的。如果此时换成equals,则相等,因为equals比较的是内容。

4.特殊的 + 号连接 字符串

(1)情景一

String str1="abc";

String str2="def";

String str3=str1+str2;


System.out.println(str3=="abcdef"); //结果肯定是为false

因为str3指向堆中的"abcdef"对象,而"abcdef"是字符串池中的对象,因为结果为false。JVM对Stringstr="abc"对象放在常量池中是在编译时做的,而Stringstr3=str1+str2是在运行时刻才能知道的。new对象也是在运行时才做的。而这段代码总共创建了5个对象,字符串池中两个、堆中三个。+运算符会在堆中建立来两个String对象,也就是说从字符串池中复制这两个值,然后在堆中创建两个对象,然后再建立对象str3,然后将"abcdef"的堆地址赋给str3。

(2)情景二和情景三

String str="abc"+"def"; //直接将"abcdef"放入字符串池中

System.out.println(str=="abcdef"); //结果为true

String str1="abc";

String str2=str1+"def"; //str1是在堆中创建的对象

System.out.println(str2=="abcdef"); //结果为false

由于字符串对象的大量使用(它是一个对象,一般而言对象总是在堆中分配内存),Java中为了节省内存空间和运行时间(如比较字符串时,==比equals()快),在编译阶段就把所有的字符串文字放到一个字符串池中,而运行时字符串池成为常量池的一部分。字符串池的好处,就是该池中所有相同的字符串常量被合并,只占用一个空间。

5. 创建字符串总结:

创建字符串有两种方式:两种内存区域(字符串池,堆)

(1)" " 引号创建的字符串在字符串池中

(2)new创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则导致浪费池的空间)

(3)对字符串进行赋值时,如果右操作数含有一个或一个以上的字符串引用时,则在堆中再建立一个字符串对象,返回引用;如Stringstr2=str1+ "abc";

比较两个已经存在于字符串池中字符串对象可以用"=="进行,拥有比equals操作符更快的速度。

四. 堆栈优劣势:

1. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享。

2. 堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: