jvm垃圾回收算法

来源:互联网 发布:一叶落而知深秋 编辑:程序博客网 时间:2024/06/06 05:40

1.对象是否存活

(1)引用计数器法

给对象添加一个引用计数器,每引用一次计数器+1,引用失效时计数器-1,当计数器计数为0时,对象不可能在被引用。

该方法无法解决对象间循环引用问题,所以jvm并没有采用这种方式

(2)可达性分析

Java采用可达性分析算法判断对象是否存活的。通过一系列名为"GC Roots"的对象作为起始点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain)当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的

GC Roots对象:a.虚拟机栈(栈桢中的本地变量表)中引用的对象(方法里引用的对象
    b.方法区中的类静态属性引用的对象c.方法区中的常量引用的对象d.本地方法栈中JNI的引用的对象 

(3)finalize()方法最终判定对象是否存活

    不可达的对象并非是非死不可的,一个对象死亡----不可达的对象经历两次标记。
  1).第一次标记并进行一次筛选:此对象是否有必要执行finalize()方法
    当对象没有覆盖finalize方法,或者finzlize方法已经被虚拟机调用过,没有必要执行,对象被回收。
  2).第二次标记
    如果这个对象为有必要执行finalize()方法,那么这个对象被放置在F-Queue队列中,jvm自动建立的、低优先级的Finalizer线程去执行。这里所谓的执行是指虚拟机会触发这个方法,但并不承诺会等待它运行结束。原因是,如果一个对象finalize()方法中执行缓慢,或者发生死循环,将很可能会导致F-Queue队列中的其他对象永久处于等待状态,甚至导致整个内存回收系统崩溃。
    Finalize()方法是对象脱逃死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象要在finalize()中成功拯救自己----只要重新与引用链上的任何的对象建立关联即可,譬如this指针赋值给某个类变量或对象的成员变量,那在第二次标记时它将移除出即将回收的集合。如果对象这时候还没逃脱,那基本上它就真的被回收了。
2、方法区垃圾回收(永久代)

在堆中,尤其是新生代中常用的一次垃圾回收器可回收75~90%的空间,而永久代的垃圾收集较低。

永久代垃圾回收主要:废弃常量无用的类(必要时会回收 可以通过设置jvm参数)

1)废弃常量

如果常量池中有“ABC”字符串常量,但当前系统中没有任何一个String对象引用常量池中的ABC,那么当发生gc时且有必要的情况下,该常量会被清理。

2)无用的类:

同时满足:a.Java堆中不存在该对象的任何实例;b.该类的ClassLoader已经被回收;c.Java.lang.class没有被引用,无法在任何地方通过反射访问该类方法。

3、垃圾回收算法

(1)标记-清除(老年代)

首先标记出所有要回收的对象,完成后统一进行清理。

两个不足:效率问题内存碎片(当需要需要分配较大对象时,无法找到连续的内存不得不提前出发gc

(2)复制(新生代)

内存分成左右两个大小相等的块,每次只使用其中一块,当用完这块将所有活着的对象复制到另一块上,然后将左边的一次清理掉。

实现简单效率高,没有碎片内存缩小为原来的一半。

实际应用中并不需要按照1:1分块,分为一个较大的Eden两个小的Survivor,每次使用Eden和一个survivor,Hotspot设置Edensurvivor比例是8:1

(3)标记-整理(老年代)

复制算法浪费空间 需要额外的空间进行担保,老年代对象存活时间长 不采用复制。

先标记要清除的对象,将所有存活的对象移动到内存一端,然后直接清理掉端边界以外的内存。没有内存碎片

(4)分代

新生代复制,老年代标记清除或者标记整理

1 0
原创粉丝点击