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

Posted yanqingguo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了垃圾收集器与内存分配策略相关的知识,希望对你有一定的参考价值。

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

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

垃圾回收的对象主要是堆内存中的对象,进行回收之前需要判断对象是否存活,如果死则回收,如果活,则不进行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%存活,需要依赖其他内存进行分担,老年代一般不采用这种算法,针对老年代的回收有标记-整理算法,先对可回收对象进行标记,然后将所有存活对象往一端移动,然后直接清理掉边界以外的把内存。

分代收集算法

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

 

以上是关于垃圾收集器与内存分配策略的主要内容,如果未能解决你的问题,请参考以下文章

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

Java虚拟机浅谈——垃圾收集器与内存分配策略

垃圾收集器与内存分配策略之垃圾收集算法

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

垃圾收集器与内存分配策略之垃圾日志与常见参数

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