本帖最后由 执迷不悟 于 2020-4-22 17:41 编辑
垃圾回收常见算法
1、引用计数法
1.1 原理 假设有一个对象A,任何对象对A进行引用,那么对象A的引用计数器+1,当引用失效时,对象A的引用计数器-1,当对象A的引用计数器为0时,就说明对象A没用被引用,那么就可以进行回收。 1.2 优缺点优点: 实时性高,不需要等到内存不足时,才开始回收,运行时判断对象计数器是否为0,进行回收。 在垃圾回收过程中应用无需挂起,如果申请内存时,内存不足,则立即报outofmember 错误。 区域性,更新对象计数器时,只会印象到该对象,不会扫描全部对象。
缺点 循环引用如:对象A维护了一个成员属性,类型是对象B,对象B中维护了一个成员属性,类型是对象A,然后分别给这两个成员属性赋值,在将对象A赋值为null,将对象B赋值为null,这样对象A和对象B就都是null,但是a和b存在引用关系,这样a和b永远不会被回收。 2、标记清除法标记清除算法,是将垃圾回收分为两个阶段,分别是标记和清楚 标记:从跟节点开始标记引用的对象 清除:未被标记引用的对象就是垃圾对象,可以被清理
2.1、原理这张图代表的是程序运行期间所有对象的状态,它们的标志位全部是0(也就是未标记,以下默认0就是未标记,1为已标记),假设这会儿有效内存空间耗尽了,JVM将会停止应用程序的运行并开启GC线程,然后开始进行标记工作,按照根搜索算法,标记完以后,对象的状态如下图。 可以看到,按照根搜索算法,所有从root对象可达的对象就被标记为了存活的对象,此 时已经完成了第一阶段标记。接下来,就要执行第二阶段清除了,那么清除完以后,剩下的对象以及对象的状态如下图所示。 可以看到,没有被标记的对象将会回收清除掉,而被标记的对象将会留下,并且会将标 记位重新归0。接下来就不用说了,唤醒停止的程序线程,让程序继续运行即可。 2.2、优缺点可以看出标记清除法解决了,引用计数法的循环引用问题,没有从root节点引用的对象都会被回收。 缺点: 3、标记压缩算法标记压缩算法是在标记清除法的基础上进行了优化,标记阶段是一样的,在清理阶段不是直接清理标记对象,而是将存活对象压缩到内存的一端,然后清理边界以外的垃圾,从而解决碎片化问题。 3.1、原理3.2、优缺点解决了标记清除法碎片化问题,同时多了压缩这一步,对象移动内存位置的步骤,其效率有一定的影响。
4、复制算法复制算法的核心就是,将原有的内存空间一分为二,每次只使用其中一块,在垃圾回收时将正在使用的对象复制到另外一个内存空间中,然后将该内存空间清空,交换两个内存角色完成垃圾回收。 如果内存中的垃圾对象较多,需要复制的对象少,这种情况下使用这个算法比较合适效率较高,反之,不合适。 4.1、JVM中年轻带内存空间在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。 紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。 经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。 GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
4.2、优缺点优点: 缺点: 在垃圾对象少的情况下,不适用,如:老年代内存 内存空间一分为二,只使用其中一个,内存使用率低
5、分代算法前面介绍了多种回收算法,每一种算法都有自己的优点也有缺点,谁都不能替代谁,所以根据垃圾回收对象的特点进行选择,才是明智的选择。分代算法其实就是这样的,根据回收对象的特点进行选择,在jvm中,年轻代适合使用复制算法,老年代适合使用标记清除或标记压缩算法
|