JVM垃圾识别和回收算法
垃圾识别算法
引用计数法
判断一个对象是否被其他对象所依赖或者引用,每有一次引用出现则在计数器中+1,每结束一次引用计数器-1。当计数器为0时表示没有被任何对象引用,则被标记为可以回收的对象,但不一定立刻被回收。缺陷:存在循环依赖的问题无法识别。
Class A{
private B bInstance;
}
Class B{
private A aInstance;
}
Class Java{
public static void main(String args[]){
A a = new Class A();
B b = new Class B();
a.setB(b);
b.setA(a);
}
}
可达性分析
从根节点(GC Root)遍历能够到达,则视为被引用,如果不能到达,则标记为可以回收的对象。
上图中的对象A、B、C、D都可以从GC根节点处搜索抵达,因此都是被引用对象。
此时对象H虽然被对象G引用,但是对象G以及可清除了,因此E、F、G、H对象都被标记为可回收对象。
哪些对象可以被视为GC Root:
- 虚拟机栈中的对象
- 本地方法中引用的对象
- 方法区中静态属性引用的对象
- 方法区中常量引用的对象
- 所有同步锁持有的对象
垃圾回收算法
标记-清除
将有可回收标记的对象直接删除。这种算法会存在内存碎片,使得存储空间不连续,下一次分配内存比较复杂。
复制-清除
将大小为N的存储空间平均分为两份,将内存A中的所有数据复制一份到内存B中,清除内存A中的数据。(Young代)
例如:新生代在垃圾回收时,先将Eden区和From区的中的存活对象(例如:标记0为可回收对象,1为存活对象)通过复制放入To区,清除Eden区和From区。再将To区对象复制到From区,清除To区。
标记-整理
将没有可回收标记的对象整理到连续的区域里,其他内存中的对象全部清除。因为多了整理这一步,所以效率不高,比较费时。(Old区)
分代回收
Java 堆一般被分为新生代和老年代,我们可以根据各个年代的特点选择合适的垃圾收集算法。
Young代:minor GC频繁,每次收集都会有大量对象死去,可以选择复制-清除算法。
Old代:GC频率不高,而且老年代的对象存活几率是比较高的,可以选择标记-整理算法。