美文网首页
JVM中的垃圾收集

JVM中的垃圾收集

作者: 游牧族人 | 来源:发表于2018-06-03 16:21 被阅读30次

    如何判断对象是否已死?

    一、引用计数算法

    为每一个对象添加一个引用计数器,当这个对象被其他对象引用时,引用计数器+1,反之-1。当对象引用计数器值为0时,证明他没有被任何对象引用,可以把他当做垃圾进行收集。
    这种算法效率很高,实现也比较简单。但是我们可以考虑一下情况,有两个对象相互引用着,而这两个对象除了引用对方就没有别的引用对象了,这时两个对象的引用计数器的值均为1,但是从逻辑上来讲,他们确实是两个无用的对象,是两个垃圾对象,但是我们的垃圾收集线程却不能收集他们。
    优:实现简单,垃圾判定效率较高。
    缺:无法判定两个相互引用的垃圾对象。

    二、可达性分析算法

    可达性分析算法是找到一些被称为GCRoot的对象最为起始点,从这些结点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GCRoot没有任何引用链时(从GCRoot到这个对象不可达),证明这个对象是垃圾对象,可以被垃圾收集线程回收。
    在Java中,可以作为GCRoot的对象包括:
    1、虚拟机栈(栈帧中本地变量表)中引用的对象
    2、方法区中类静态属性引用的对象
    3、方法区中常量引用的对象
    4、本地方法栈中Native方法(JNI)引用的对象

    finalize方法的执行流程:

    当垃圾收集线程发现一个对象到GCRoot没有引用链时,该对象会被视为垃圾对象,进而JVM会判断该对象是否有必要执行finalize方法,若有必要执行finalize方法(当对象重写了finalize方法并且没有被虚拟机调用过则判定为有必要执行finalize方法),那么对象会被放置一个F-Queue队列中,并在稍后虚拟机建立的低优先级的Finalizer线程中执行对象的finalize方法。对象可以在finallize方法中关联一个其他对象的引用,这样他就可以免除一死……遍历完F-Queue中的对象后,垃圾收集线程会稍后再次查找队列中对象是否再次引用了其他对象,若引用了其他对象并且可达GCRoot,那么他就不会被GC清理掉,否则他就必须GG了。
    PS:finalize方法最多只能被执行一次!!!
    对象即将死亡时通过finalize方法自救成功后,当他再次被垃圾收集器收集时,不会再执行finalize方法。

    垃圾收集算法

    一、标记---清除算法

    算法过程:首先标记处所有需要收集的垃圾对象,随后统一回收标记过的垃圾对象。


    垃圾回收前状态
    垃圾回收后状态
    image.png

    优点:所有垃圾收集算法的母体
    缺点:
    ①标记和清除两个过程的效率不高
    ②空间碎片化严重

    二、复制算法

    复制算法将内存空间等分为两部分,每次只占用其中的一部分,当这部分内存空间使用完后,执行一次垃圾收集动作,将存活的对象复制到另一部分内存区域,然后将第一部分的内存区域全部清理,这样每次进行一半内存的垃圾回收,解决了空间碎片化问题,但是这种方法狠狠的压缩了虚拟机可用内存。


    优点:标记--清除算法的改进,有效的解决了空间碎片化问题。
    缺点::
    ①压缩了不少可用内存区域
    ②当有大量对象存活时,需要进行较多次数的复制操作,效率会降低

    三、标记---整理算法

    标记---整理算法是标记---清除算法的升级版,而且他不需要我们腾出一般的内存空间进行对象的复制。
    标记整理算法第一阶段同标记清除算法一样,标记所有垃圾对象,但后续不直接对垃圾对象进行回收处理,而是让所有的存活对象向一段移动,然后直接清理掉边界以外的内存。


    四、分代收集算法

    根据对象的存活周期不同将Java内存区域分为新生代和老年代,对不同的区域使用不同的垃圾收集算法,新生代对象存活时间段,每次垃圾收集都会有大量对象死去,所以可以使用复制算法进行垃圾收集。老年代对象存活率高,存活时间长,所以可以使用标记---清除或标记---整理算法清除。

    相关文章

      网友评论

          本文标题:JVM中的垃圾收集

          本文链接:https://www.haomeiwen.com/subject/wtpjsftx.html