日期:2014-05-20  浏览次数:20776 次

java中怎么理解“堆空间”和“栈空间”?
一:java中怎么理解“堆空间”和“栈空间”?
二:还有实例化对象的时候是怎样开辟内存空间的?
三:引用对象内存怎么分配和指向?

这些数据结构问题老是犯浑,平时都不没接触过,面试问到一句都说不出,请知道的朋友帮忙解释下。
能画个内存指向图更好....

------解决方案--------------------
程序执行的过程
程序从硬盘载入的内存->有四个内存区供程序使用
heap(堆 ),stack(栈),data segment,code segment
heap堆:用来存放new出来的东西
stack栈:局部变量。
data segment:静态变量,字符串常量。
code segment:存放代码

------解决方案--------------------
首先回2楼,不要看中国人写得书,虽然中国文化源远流长,但是计算机这方面还是不要看中国人写的,毕竟有差距,而且中国人写的书很多都存在误导。
回楼主,首先解释一下虚拟机内存:
java虚拟机存在方法区,堆空间与栈空间,定义是这样的,虚拟机具体实现完全可以把它们分开在不同内存中,也可以把它们放在同一段内存中。
方法区存放类与方法。
堆空间存放实例化的对象。
栈空间有两种,一种是方法栈,虚拟机会为每个线程所调用的方法申请空间,而这个栈就是这些空间,另外一个是操作数栈,两个局部变量或者成员变量需要进行处理的时候,执行语句会吧这两个变量的值放入操作数栈中进行处理,处理完成以后会将处理结果弹出栈。
了解了这些后其实那些问题都不难:
第一个问题上面说得很清楚了。
第二个问题,当虚拟机生产对象的时候会申请内存空间(怎么申请的,你去看汇编程序设计以及寄存器寻址方式),然后如果引用是静态成员变量,则引用放在方法区中,如果引用是成员变量则放在堆中,如果引用是局部变量,则成为局部变量索引(局部变量没有变量名称,它只是一个索引项)。
第三个问题,虚拟机规范没有规定引用应该去怎么实现,如今应用大致有两种实现方式,一种是引用直接就是一个指向堆内存的指针,另外一个是引用指向方法区类对象映射表中的某个项,映射表中的项再以指针的形式指向堆内存空间,具体实现可能还有更多情况,所以这个问题你不必太过于探讨。

------解决方案--------------------
前几天看了栈堆内存:
总结了下:有些是根据网上总结的(由于时间的问题,还没结完)
有错的地方希望提出 毕竟我也是新手 总结不好的地方不要拍砖!
Java code

栈内存:
     在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 栈内存主要存放的是基本类型类型的数据 如、( int, short, long, byte, float, double, boolean, char) 和对象句柄。并没有有String基本类型、在栈内存的数据的大小及生存周期是必须确定的、其优点是寄存速度快、、栈数据可以共享、缺点是数据固定、不够灵活。

 栈的共享:
   
                  String a = "abc";
        String b = "abc";
        System.out.println(a==b);
       结果为true 这就说明了a b其实指向同一个值
注意,我们这里并不用a.equals(b);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,a与b是否都指向了同一个对象。 
结果说明,JVM创建了两个引用a和b,但只创建了一个对象,而且两个引用都指向了这个对象。

首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有abc这个值,如果没找到,就将abc存放进来,然后将a指向abc。接着处理String b = "abc";在创建完b的引用变量后,因为在栈中已经有abc这个值,便将b直接指向abc。这样,就出现了a与b同时指向abc
特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与b的值后,再令a=abcd;那么,b不会等于abcd,还是等于abc。在编译器内部,遇到a= abcd;时,它就会重新搜索栈中是否有abcd的字面值,如果没有,重新开辟地址存放abcd的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。
堆内存:
   堆内存用来存放所有new 创建的对象和 数组的数据、

        String a = new String ("abc");
        String b = "abc";
        System.out.println(a==b);  //False
String a = new String ("abc");
String b = new String ("abc");
System.out.println(a==b);  //False

创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。

------解决方案--------------------
探讨
前几天看了栈堆内存:
总结了下:有些是根据网上总结的(由于时间的问题,还没结完)
    有错的地方希望提出 毕竟我也是新手 总结不好的地方不要拍砖!
 Java code
栈内存:
    在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 栈内存主要存放的是基本类型类型的数据 如、( int, short, long, byte, float, double, boolean, char) 和对象句柄。并没有有String基本类型、在栈内存的数据的大小及生存周期是必须确定的、其优点是寄存速度快、、栈数据可以共享、缺点是数据固定、不够灵活。

栈的共享:
 
                  String a = "abc";
String b = "abc";
System.out.println(a==b);
      结果为true 这就说明了a b其实指向同一个值
注意,我们这里并不用a.equals(b);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,a与b是否都指向了同一个对象。
结果说明,JVM创建了两个引用a和b,但只创建了一个对象,而且两个引用都指向了这个对象。

首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有abc这个值,如果没找到,就将abc存放进来,然后将a指向abc。接着处理String b = "abc";在创建完b的引用变量后,因为在栈中已经有abc这个值,便将b直接指向abc。这样,就出现了a与b同时指向abc
特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与b的值后,再令a=abcd;那么,b不会等于abcd,还是等于abc。在编译器内部,遇到a= abcd;时,它就会重新搜索栈中是否有abcd的字面值,如果没有,重新开辟地址存放abcd的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。