参考《深入理解Java虚拟机第三版》
垃圾识别算法
引用计算算法
注意:主流JVM都没用使用引用计数算法来管理内存。主要原因是有很多例外的情况需要考虑,必须配合大量的额外处理才能保证正确的工作。
在对象添加一个引用计算器,引用它时+1,引用失效-1;
优点1:原理简单
优点2:效率高
缺点1:占用额外的内存
缺点2:有很多例外情况不能解决,如无法解决对象相互引用的问题
可达性分析算法
主流JVM是用可达性分析算法来管理内存的。
可达性算法的原理是以一系列叫做 GC Root 的对象为起点出发,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),直到所有的结点都遍历完毕,如果相关对象不在任意一个以 GC Root 为起点的引用链中,则这些对象会被判断为「垃圾」,会被GC 回收。
即使在可达性分析算法中判定为不可达的对象,也不是“非死不可”的,这时候它们暂时还处于“缓 刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没 有与GC Roots相连接的引用链,那它将会被第一次标记,随后进行一次筛选,筛选的条件是此对象是 否有必要执行finalize()方法。假如对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用 过,那么虚拟机将这两种情况都视为“没有必要执行”。
任何一个对象的finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法不会被再次执行。
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive() {
System.out.println("yes, i am still alive :)");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method executed!");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws Throwable {
SAVE_HOOK = new FinalizeEscapeGC();
//对象第一次成功拯救自己
SAVE_HOOK = null;
System.gc();
// 因为Finalizer方法优先级很低,暂停0.5秒,以等待它
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no, i am dead :(");
}
// 下面这段代码与上面的完全相同,但是这次自救却失败了
SAVE_HOOK = null;
System.gc();
// 因为Finalizer方法优先级很低,暂停0.5秒,以等待它
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no, i am dead :(");
}
}
}
垃圾回收算法
标记-清除算法
缺点:
1、执行效率不稳定
如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低
2、内存空间碎片化
标记、清除之后会产生大 量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
标记-复制算法
标记-整理算法
在垃圾-清除算法基础上对存活的对象进行了复制,但是会多使用一半的内存,以及消耗大量的内存复制的时间。若存活的对象较多,一般不使用该算法,如老年代。
标记-整理算法
解决了内存碎片化的问题,在标记清除后,存活的对象向内存空间的一端移动,然后清理掉边界以外的内存。
移动存活对象,效率十分低下,而且这种方式需要暂定用户应用程序才能进行。
分代收集理论
基于分代收集的理论,发展出了上面的算法。
在堆内存里,一般分为新生代和老年代,每次垃圾收集时新生代里大量的对象会死去,剩余存活的的对象晋升到老年代中存放。
新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。
老年代收集(Major GC/Old GC):指目标只是老年代的垃圾收集。
目前只有CMS收集器会有单独收集老年代的行为。
混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有G1收 集器会有这种行为。
整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。