标签:nbsp 垃圾收集 完成 root 失效 变量 可用内存 引用计数器 说明
本文参考《深入理解虚拟机》一书
垃圾回收的对象主要是堆内存中的对象,进行回收之前需要判断对象是否存活,如果死则回收,如果活,则不进行GC。
给对象添加一个引用计数器,每当有一个地方引用它,计数器的数字就加一,引用失效时,计数器值就减一,任何时刻计数器值为0的对象就是不可能再被使用的对象,但是它很难解决对象之间相互循环引用的问题。
通过一系列称为"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%存活,需要依赖其他内存进行分担,老年代一般不采用这种算法,针对老年代的回收有标记-整理算法,先对可回收对象进行标记,然后将所有存活对象往一端移动,然后直接清理掉边界以外的把内存。
针对新生代和老年代的特点采用针对的回收算法,新生代死亡率高,所有使用复制算法,老年代存活率高,没有额外空间进行担保,使用标记-清理或者标记-整理算法。
标签:nbsp 垃圾收集 完成 root 失效 变量 可用内存 引用计数器 说明
原文地址:https://www.cnblogs.com/yanqingguo/p/9746624.html