Java堆与堆栈理解总结

Java将内存分为两种:一种是栈内存,一种是堆内存。

1、  栈(stack)与堆(heap)都是Java用来在Ram(随机存取存储器)中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

2、栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(int, short, long, byte, float, double, boolean, char)和对象句柄。JVM规范让每个Java线程拥有自己的独立的JVM栈,也就是Java方法的调用栈(多个线程共享堆)在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。

堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

3、存储在栈中的数据可以共享。

假设定义:int a = 3,b = 3.

①  编译器先处理a = 3。首先它会在栈中创建一个变量为a的引用,然后在查找有没有字面值为3的地址,如果没有,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。

②  顺序下来,接着就是处理b = 3。在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样就出现了a与b同事均指向3的情况。

③  特别注意的是,这种字面值的引用于类对象的引用不同,通过字面值的引用来修改值,不会导致另一个指向此字面值的引用的值也跟着变化。如果此时我们让a = 4,那么它会重新搜索栈中是否有4的字面值,如没有,就重新开辟地址存放4的值;如有,则直接将a指向这个地址。

此外,String是一个特殊的包装类数据。可以用: 

String str = new String("abc"); 

String str = "abc"; 

两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 

而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。 

因此:

情况一: 

String str1 = "abc"; 

String str2 = "abc"; 

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

情况二: 

String str1 =new String("abc"); 

String str2 =new String("abc"); 

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

情况三: 

String s1 = "ja"; 

String s2 = "va"; 

String s3 = "java"; 

String s4 = s1 + s2; 

System.out.println(s3 == s4);//false 

System.out.println(s3.equals(s4));//true 

4、引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因。

你可能感兴趣的:(java)