• 垃圾收集器与内存分配策略


    本文参考《深入理解虚拟机》一书

    虚拟机判断对象是否已经死亡?

    垃圾回收的对象主要是堆内存中的对象,进行回收之前需要判断对象是否存活,如果死则回收,如果活,则不进行GC。

    判断对象是否能进行回收的算法

     过去的算法:引用计数算法

    给对象添加一个引用计数器,每当有一个地方引用它,计数器的数字就加一,引用失效时,计数器值就减一,任何时刻计数器值为0的对象就是不可能再被使用的对象,但是它很难解决对象之间相互循环引用的问题。

    主流算法:可达性分析算法:

    通过一系列称为"GC Roots"的对象,从这些对象开始往下进行搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,证明此对象不可用。

    GC Roots对象种类:

    虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、Native引用的对象

    上面是对什么样的对象进行回收和进行回收使用的算法思想,可达性分析算法只是说明一些不符合条件的对象不可用,但是并没有宣判这个对象的死期到来,它还是有机会复活的,如果有不符合可达性分析的对象,这个对象将会被标记一次,此时它处于缓刑阶段,这是是否判处对象死刑需要判断对象是否执行过finalize方法,当对象没有覆盖finalize方法或者虚拟机已经调用过finalize方法,这是就不需要执行finalize方法,这个对象就被宣判死刑,需要被回收。如果对象执行了finalize方法 ,在方法中可以进行自我拯救,只需要将自己赋值给某个类变量或者对象的成员变量,那么这个对象将从即将进行垃圾回收的集合中移除,完成了自我拯救,finalize方法对于每个对象来说只能执行一次。

    方法区的垃圾回收

    方法区回收的对象主要是常量池中的废弃常量,方法和堆中非常类似,比如一个字符串“abc”,如果没有任何引用指向abc,那么abc将会被系统清理出常量池。

    垃圾回收算法

    标记-清除算法

    标记处需要清除的对象,然后进行清除,但是效率不高,产生的空间碎片多。

    复制算法

    将可用内存分为两块,一块使用完后,将存活的对象复制到另一块内存上,然后将已经使用过的内存空间进行清除,这样每次都对半个内存进行回收,而且不会产生空间碎片问题。

    但是一次性损失50%的内存空间,得不偿失,所以对复制算法进行了改进,将内存分为一个较大的Eden区和两个较小的Survivor区,每次使用Eden和一个Survivor区,进行垃圾回收时,将Eden和Survivor存活对象一次性复制到另一个Survivor区,Eden的大小比例是8:1,这样一次只会造成10%的内存浪费。当然,我们不能保证每次回收只有不多于10%的对象存活,当Survivor区不够用时,需要依赖其他内存(老年代)进行分配担保。

    标记-整理算法

    复制算法需要进行较多复制操作,效率会受影响,而且如果对象100%存活,需要依赖其他内存进行分担,老年代一般不采用这种算法,针对老年代的回收有标记-整理算法,先对可回收对象进行标记,然后将所有存活对象往一端移动,然后直接清理掉边界以外的把内存。

    分代收集算法

    针对新生代和老年代的特点采用针对的回收算法,新生代死亡率高,所有使用复制算法,老年代存活率高,没有额外空间进行担保,使用标记-清理或者标记-整理算法。

  • 相关阅读:
    论文笔记:语音情感识别(五)语音特征集之eGeMAPS,ComParE,09IS,BoAW
    《Grammar and Punctuation》课堂笔记
    《Sequence Models》课堂笔记
    【翻译】学术写作中的数字
    生成器
    使用序列生成字典
    字典 (dictionary) 的默认值
    如何阅读文献 (How to Read a Paper)
    Python 列表的连接和联合
    《Convolutional Neural Networks》课堂笔记
  • 原文地址:https://www.cnblogs.com/yanqingguo/p/9746624.html
Copyright © 2020-2023  润新知