Gc回收算法

Posted by Solace Blog on March 19, 2019

判断对象是否“存活”

首先,在发生GC时需要先确定哪些对象是否可以被回收,一般可以使用下面两种方法来区别:

引用计数法

该方法是针对每个对象添加一个计数器,每次引用一次计数器就+1;引用失效一次-1;当计数器变为0时该对象不能再被引用,此时该对象可确定为已”死去“。

但Java并未使用此方法来判断对象是否“存活”,原因是当出现相互循环引用时,这种方法并不奏效。

可达性分析算法

所以现在主流语言都使用此算法来判断对象是否“存活”,它的思想是:有一种称为”GC Roots”的对象作为起始点,从这些起始点开始向下搜索,搜索所有过的所有路径称为“引用链”(Reference Chain)。

当一个对象所在的引用链没有与任何“GC Roots”相连时,就认定该对象是可回收的对象。

垃圾回收算法

当确定一个对象可以被回收时,就会发生GC,在JVM中,在不同区域GC的方法也不同。

标记-清除法(Mark-Sweep)

是最基础的算法,主要有两个步骤:先标记出需要清除的对象,然后进行统一清除掉,存在的主要问题是内存碎片化

复制算法(Copying)

将内存划分为两块大小完全相等的区域,只使用其中一块区域。当发生GC时,先将存活的对象复制到未使用的区域中,然后全部清除所有剩下的对象。

这样简单高效,并且不会出现标记-清楚算法的问题,唯一缺点就是太浪费内存,且当存活对象较多时,效率会明显减低。

标记-整理算法(Mark-Compact)

标记-整理的前面和编辑-清除一样,只是后面不是直接将对象清除,而是先让存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

分代收集算法

这种算法并没有什么新的思想,只是根据对象存活周期的不同,将内存划分为不同区域的几块,比如新生代、老年代,然后针对不同的区域使用不同的回收算法。对于新生代,只有少量对象存活,那就使用复制算法进行回收;对于老年代的对象存活率都比较高,所以使用标记-清除或者标记-整理算法进行回收。

JVM采用这种算法:新生代存活对象少,使用复制算法;老年代每次回收的对象较少,因此使用的就是标记-整理算法来回收对象。