上图就是JVM的分代模型,JVM根据Object的生命周期长短,将其分为上述的三个层次(也称代)。不同的层次,其GC(收集回收)算法不一样
- Young Generation(年轻代、young代)
对象的初次创建就会在young代,大部分对象在创建后不再被使用,于是就会被年轻代的GC机制清理掉,这个GC叫做Minor GC或Young GC(注意:1、这是一个停顿动作;2、这并不表示年轻代内存不足,仅表示Eden区满了,发生GC)。
年轻代包括:Eden区+两个存活区(S0和S1,即上图中from和to)。young gc机制如下图:
- 大部分对象在创建完后就会被分配在Eden区,使用完被销毁
- 当Eden区满的时候,执行Minor GC,将可销毁的对象清除掉,将剩余不可销毁的对象迁移到存活区S0
- 每次Eden发生Minor GC时,剩余存活对象都会到S0区(此时S1区空白)
- 当S0区满的时候,会将其中仍然存活的对象复制到S1,同时Eden发生Minor GC时,剩余对象都会到S1区(此时S0区空白)
- S0和S1会来回复制存放(总有一个是空白),但某对象来回存放次数超过15次(-XX:MaxTenuringThreshold设置的值,默认是15),则不再存在young代,将被存放到old代
- 当Minor GC时,存活的对象大过S0区的大小,则会直接进入old代
总结下:
Eden区是一个连续的空间,并且S区总有一个空白的。经过一次GC和复制后,一个S区保留存活对象,而Eden区和另一个S区可直接清空,到下一次GC时,两个S区的角色互换。这就是著名的“停止-复制(Stop-and-copy)”清理法。
- Old Generation(年老代、old代)
对象如果在young存活了足够长的时间(多次Minor GC,仍未能销毁),则会被复制到old代,old代的空间一般比young代大,能够存放更多的对象,一般来说old代上GC次数也比young代少。当old年代空间不足时,将执行Major GC,也叫Full GC。
old代的对象销毁并非跟young代一样,而是通过标记-整理算法,即:标记出仍然存活的对象(存在引用的),将所有存活的对象向一端移动,以保证内存的连续。
但当young代进入old代时,如果进入old代的对象大小大于old代剩余空间大小,则会直接触发一次Full GC(可通过-XX:+HandlePromotionFailure额外设置)
题外话:可能存在old代的对象引用young代对象的情况,old代会维护一个512 byte的块“card table”,里面保存old代的对象引用young代对象的记录,当young gc时,只需查这里,不用遍历整个old代对象
- Permanent Generation(持久代)
主要存放代码(字节码),字符串常量池,静态变量,可持久化的数据等;
每次Full GC时,同时也会销毁掉持久代中可销毁的对象
什么是可销毁的对象?
所有的Java对象构成一颗近似“搜索树”的结构,有一个root根节点,每次从root出发向下搜索,当整个树遍历完成后,那些不在其中的变量则视为"垃圾"。
如上图所示,红色部分对象均属于可删除对象
什么是java的root节点?
所有正在运行的线程的栈上的引用变量。所有的全局变量。所有ClassLoader
知乎回答: https://www.zhihu.com/question/50381439
接下来总结的是:GC算法和部分JVM参数讲解