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

堆与栈
在书本中看到这么一句话:
1.在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。
比如说people z=new people("张三"); //z引用在栈内存中分配,new表达式的内容在堆内存分配,是吗??
那这样堆与栈怎么联系起来啊??有点疑惑
2.int a = 3; 编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。 (这里写的,怎么感觉a是个引用啊)
在栈内存中,a本身有没有分配内存啊?还是a直接是个变量名而已?
感觉对jvm的堆与栈存储理解的还不是很清楚。。。。。。。

------解决方案--------------------
引用类型的引用存在栈中,存的是一个地址,这个地址指向堆内存,就是堆内存的首地址。

基本类型不存在什么引用的概念,只是就是在栈中存一个a=3的值。int b=3,另外分配一个空间使b=3.
建议看深入Jvm,别被其他文章干扰。


引用.......
------------------------------
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
//栈都是由运行环境来处理的,这点C++和java没有什么不同.对于堆,不过java多了个GC.
2.这里的堆和栈首先要明确是虚拟机栈,和寄存器根本不是一个级别的东西,就别比较了.
3.栈数据共享好像是作者自己创造的概念.而且给基本类型也引入了"引用"的概念,不知道出于何种打算.
java虚拟机规范中说:Primitive values do not share state with other primitive values. A variable whose type is a primitive type always holds a primitive value of that type.
看一下实际的处理情况:
int a=3;
int b=3;
int c=65535;
int d=65535;
int e=32330;
int f=32330;
看对应的虚拟机指令,可以知道变量里实际存储的是什么:
Code:
0: iconst_3 //3
1: istore_1
2: iconst_3 //3
3: istore_2
4: ldc #2; //int 65535
6: istore_3
7: ldc #2; //int 65535
9: istore 4
11: sipush 32330
14: istore 5
16: sipush 32330
19: istore 6
21: return
可以看出每个变量保存自己的值.(具体指令的意义参考java虚拟机规范)
这里要注意的是对于int值,如果它大于short能表示的范围,则放到常量池中去.
11: sipush 32330
14: istore 5
这句,11-13,正好是3个字节的指令大小,一个字节是sipush指令,2个字节用来存储32330这个数.两次使用到这个数,都是把它直接存给变量的,所以原贴中一直强调的"栈中共享" 的说法明显不对.
对于65535,它是大于两个字节的,编译的时候把它放入常量池部分,而把取这个数的指令写为ldc#2,我感觉这样一个直观的好处是减少了指令代码的长度.尤其是多次使用到一个相同的数时.

其实,java 对变量的处理很简单,基本类型变量存放值,引用类型存放一个"引用" (实际就是一个"指针" ,以前曾经和别人讨论过,很多人认为是个"句柄",并举了很多证据,但是我后来看到了sun的java hotspot白皮书,里面直接说明了,引用实际就是一个c的"指针" ,使用句柄需要多次间接查找,会带来效率的瓶颈,当然这个指针并不是直接指向实际的对象,实际指向的是一个两个机器字大小的对象头,对于数组是3个机器字大小的对象头,因为还要保存数组的长度) .

------解决方案--------------------
1、是,new创建的对象保存在堆中,引用z保存在栈中,z是个引用变量,直接指向堆中保存的对象
2、a在栈中也分配内存,创建a的同时就已经分配内存,a就是个变量(变量值为3,也可以认为a是个引用,指向字面值为3的地址,在调用变量a的过程中应该也是先找地址)
------解决方案--------------------
http://deng5566.iteye.com/blog/665942
LZ看下这文章