GC处理的深入分析
在Java中针对垃圾收集也提供了多种不同的处理分类
1.引用计数:
一个实例化对象,如果有程序使用了这个引用对象,引用计数加一,当一个对象使用完毕,引用计数减一,当引用计数为0时,则可以回收;
2.跟踪收集:
从root set(包括当前正在执行的线程、全局变量或者静态变量、JVM Handles、JNDI Handles)开始扫描有引用的对象,如果某个对象不可到达,则说明这个对象已经死亡(dead),则GC可以对其进行回收。也就是说:如果A对象引用了B对象的内存,那么虚拟机会记住这个引用路径,而如果一个对象没有在路径图中,则就会被回收。
3.基于对象跟踪的分代增量收集:
所有的对象回收都要根据堆内存的结构划分来进行收集,具体如下:
基于对象跟踪:
是由跟踪收集发展而来的,分代是指对堆进行了合理的划分,JVM将整个堆分成以下三代:
YoungGen(新生代,使用Minor GC回收):
YoungGen区里面的对象的生命周期比较短,GC对这些对象进行回收的时候采用复制拷贝法。
young:又分为eden、survivor1(from space)、survivor2(to space)。eden是在每个对象创建的时候才会分配的空间,当eden无法分配时,则会自动触发一次Minor GC。当GC每次执行时都会将eden空间中存活的对象和survivor1中的对象拷贝到survivor2中,此时eden和survivor1的空间内存将被清空。当GC执行下次回收时将eden和survivor2中的对象拷贝到survivor1中,同时会清空eden和survivor2空间。按照此类的顺序依次执行,经过数次回收将依然存活的对象复制到OldGen(老年代)区。
OldGen(老年代,使用Major GC回收):
当对象从YoungGen保存到OldGen后,会检测OldGen的剩余空间是否大于要晋升对象的大小,此时会有以下两种处理形式:
- 如果小于要保存的对象,则直接进行一次Full GC(对整个堆进行扫描和回收,但是Major GC除外),这样就可以让OldGen腾出更多的空间。然后执行Minor GC,把YoungGen空间的对象复制到OldGen空间。
- 如果大于要保存的对象,则会根据条件(HandlePromotionFailure配置:是否允许担保分配内存失败,即整个OldGen空间不足,而YoungGen空间中Eden和Survivor对象都存活的极端情况。)进行Minor GC和Full GC回收。
PermGen(持久区):
要存放加载进来的类信息,包括方法、属性、对象池等,满了之后可能会引起Out Of Memory错误。
MetaSpace(元空间):持久化的替换者,直接使用主机内存进行储存。
增量收集:
不是每一次都全部收集,而是累积的增量收集。