黑马程序员技术交流社区

标题: 堆和栈的问题 [打印本页]

作者: xieshuhua    时间: 2012-5-14 22:58
标题: 堆和栈的问题
大家帮忙看下,我总结的CPU运行过程正确吗?箭头是cpu的读取顺序。
我理解栈就是一个运动的过程,1,2,3,4,5有顺序,存在即会执行。所以栈有先进后出的特性,而且动作结束,系统就会自动回收了。
我的问题是:类实例化的时候,对象获得堆数据地址的同时,ss是否也获取了栈的数据地址?
ss运行结束后,还会保留其数据地址吗(下面的程序是否会引用未知)?
我理解堆是一个存放各种地址的集合,能new的都会存在堆中。存放数组所有成员的地址(数组成员的地址指向常量池或者其他变量地址),存放类成员的地址(变量,动作等)
CPU访问堆的时候,没有顺序,通过指针的偏移访问特定的变量(xx.yy就是将指针偏移到xx的yy方法并读取yy方法的地址)。所以栈就有灵活性的特点。Java通过gc进行回收,回收动作慢。
我的问题是:是不是栈直接一次运行里面的数值就会被销毁,堆里的内容需要反复判断再决定是否将内容销毁(这个有点高级啊)。
写了很多肯定有不对的,大家帮我指点下啊,谢谢啦。

xxx.png (46.07 KB, 下载次数: 45)

xxx.png

作者: xieshuhua    时间: 2012-5-14 23:07
大家有没有这种资料啊,介绍下~~
作者: xieshuhua    时间: 2012-5-14 23:27
可能写的太多了,大家多多见谅,我真的很想和大家讨论这方面问题。感兴趣的 我们在这里面相互讨论,共同提高。
作者: xieshuhua    时间: 2012-5-14 23:37
下图是我找的一个资料上面的介绍,可是我们一般认为3是存在常量池中的啊,大家怎么理解?

3333.png (15.9 KB, 下载次数: 46)

3333.png

作者: hongbo    时间: 2012-5-14 23:42
数据是先进入jvm的栈的,如果有new出现(即对象)的时候,就会有一个堆的地址赋给栈中,当堆中没有栈所调用的数据的时候,栈就会把内存释放。而堆中,如果不再有栈中的数据调用,就会被视为垃圾,但是不会被立即销毁,要等到jvm空闲的时候,利用java的回收机制,回收
作者: 秦晓阳    时间: 2012-5-15 01:12
1,static静态方法,应该存放在静态方法区中,这样才可以直接类名调用。ss方法只有在被调用时才会进栈,不会在创建对象或者类加载就直接进栈。
2,ss运行结束之后,毫无因为会弹栈。
3,栈内运行的数据一旦执行完毕,就会立即弹栈,释放内存;而堆中的数据一旦没有被指向时,就会立即变成垃圾,等待垃圾回收机制的回收。
作者: xieshuhua    时间: 2012-5-15 08:22
hongbo 发表于 2012-5-14 23:42
数据是先进入jvm的栈的,如果有new出现(即对象)的时候,就会有一个堆的地址赋给栈中,当堆中没有栈所调用 ...

堆中没有栈所调用的数据?
这种情况出现,编译不能通过吧。没有需要的数据怎么运行哪?
作者: xieshuhua    时间: 2012-5-15 08:42
秦晓阳 发表于 2012-5-15 01:12
1,static静态方法,应该存放在静态方法区中,这样才可以直接类名调用。ss方法只有在被调用时才会进栈,不 ...

嗯,你说的很全面。
总结下,ss在类初始化的时候存放在静态方法区中,使用就会压入到栈中,使用结束就弹栈。
如果是非静态ss有是怎么样的哪?新建个对象后,ss会数据初始化吗?
另外我写的CPU运行过程正确吗?
作者: 孙峰    时间: 2012-5-15 09:28
你那个数组赋值语句不对吧,应该是{}的。
作者: xieshuhua    时间: 2012-5-15 11:47
孙峰 发表于 2012-5-15 09:28
你那个数组赋值语句不对吧,应该是{}的。

嗯嗯,我写错了,呵呵
作者: 贠(yun)靖    时间: 2012-5-15 12:26
其实你那执行过程是有问题的。因为你给ss方法设置的static的 也就是静态的  凡是加static的成员属性和方法 都会存储在方法区的静态方块里面
堆内存中一般是存放  new出来的对象的    栈内存是存放变量和引用变量的  

作者: xieshuhua    时间: 2012-5-15 12:48
贠(yun)靖 发表于 2012-5-15 12:26
其实你那执行过程是有问题的。因为你给ss方法设置的static的 也就是静态的  凡是加static的成员属性和方法  ...

把ss设置为非静态,其他地方还有没有错误啊,就怕自己把错误的东西当成正确的。因为这些知识是我从网上总结的,不是从书上摘抄的。准确性没法保证。
作者: 秦晓阳    时间: 2012-5-16 11:37
谢述华 发表于 2012-5-15 08:42
嗯,你说的很全面。
总结下,ss在类初始化的时候存放在静态方法区中,使用就会压入到栈中,使用结束就弹 ...

非静态ss方法是随着类的加载而存在的,在方法区中。创建对象时会在对象中存在一个ss方法,如果这个方法是对象特有的就可以定义方法体,覆盖原ss方法,和方法区中的ss方法无关。
作者: xieshuhua    时间: 2012-5-16 11:50
秦晓阳 发表于 2012-5-16 11:37
非静态ss方法是随着类的加载而存在的,在方法区中。创建对象时会在对象中存在一个ss方法,如果这个方法是 ...

嗯,你说的是静态和非静态加载的区别,CPU中运行的顺序又是怎么样的啊,我写了这么多,没有人肯定也没有人否定,好迷茫。。。
作者: 永恒之翼网络    时间: 2012-5-17 00:02
楼主的理解完全错误。就楼主的代码上一个图吧。
作者: 永恒之翼网络    时间: 2012-5-17 00:06
楼主的理解是错误的,就楼主的代码上个图吧。
作者: 杨康    时间: 2012-5-17 00:16
表示还没看到这,飘过。。。
作者: xieshuhua    时间: 2012-5-17 00:31
永恒之翼网络 发表于 2012-5-17 00:06
楼主的理解是错误的,就楼主的代码上个图吧。

太感谢了,画的真的很详细。不过我还是有不懂的地方,你能不能提供下这些知识的来源啊(出自那本书之类的),我自己去补充这方面知识。万分感激!
作者: 永恒之翼网络    时间: 2012-5-17 14:41
常说的JVM的内存了。它主要分为五个部分——
1、Heap (堆):一个Java虚拟实例中只存在一个堆空间
2、Method Area(方法区域):被装载的class的信息存储在Method area的内存中。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件内容并把它传输到虚拟机中。
3、Java Stack(java的栈):虚拟机只会直接对Java stack执行两种操作:以帧为单位的压栈或出栈
4、Program Counter(程序计数器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的饿地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。  
5、Native method stack(本地方法栈):保存native方法进入区域的地址
以上五部分只有Heap 和Method Area是被所有线程的共享使用的;而Java stack, Program counter 和Native method stack是以线程为粒度的,每个线程独自拥有自己的部分。
举个例子:当在程序中生成对象时,正常对象会在年轻代中分配空间,如果是过大的对象也可能会直接在年老代生成(据观测在运行某程序时候每次会生成一个十兆的空间用收发消息,这部分内存就会直接在年老代分配)。年轻代在空间被分配完的时候就会发起内存回收,大部分内存会被回收,一部分幸存的内存会被拷贝至Survivor的from区,经过多次回收以后如果from区内存也分配完毕,就会也发生内存回收然后将剩余的对象拷贝至to区。等到to区也满的时候,就会再次发生内存回收然后把幸存的对象拷贝至年老区。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2