jvm垃圾回收

365 阅读7分钟

本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力

垃圾回收

java中的垃圾回收指的是对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。内存里大部分的对象都是随着方法的执行而创建,方法执行完毕后这些对象就不会被再次使用了,但是这些生成的对象不会被清除掉,所以我们内存里面的对象会越来越多,这时我们就需要一种机制把这种不会被再次使用的对象清除掉,而这种不会被再次使用的对象我们就称之为垃圾。

垃圾对象的判定

jvm的GC工作主要针对的对象是堆内存,在做GC工作之前,首先要判定堆内存中的对象实例是否为垃圾,通常使用以下两种算法:引用计数法和可达性分析法。

引用计数法

引用计数法是为对象添加一个引用计数器,然后用一块额外的内存区域来存储每个对象被引用的次数,当对象每有一个地方引用它时,那我们对该对象的引用计数就会加1,反之每有一个引用失效时,我们对该对象的引用计数就会减1, 当对象的被引用次数为0时,那么我们可以认为这个对象是不会被再次使用了,通过这种方式我们能快速直观的定位到这些可回收的对象,从而进行清理。

引用计数法的缺点

1、无法解决循环引用的问题

当存在对象循环引用的时候,比如A对象引用了B,B对象引用了A,除此之外他们两个没有被任何其他对象引用,那么其实这部分对象也属于“可回收”的对象,但是通过引用计数法是没办法定位的。

2、另外一个方面是引用计数法需要额外的空间记录每个对象的被引用的次数,这个引用数也需要去额外的维护。

可达性分析法

使用一系列的GC Roots的对象(包括:虚拟机栈中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,本地方法栈中JNI引用的对象)作为起点,从节点开始向下搜索,当没有被GCRoots链接到的对象就可以回收,如下图

捕获.PNG

垃圾回收算法

通过可达性分析法来定位对象是否存活后,就需要通过某种策略把这些已死的对象进行清理、然后对存活的对象进行整理,这个过程就涉及到三种算法,分别为标记清除法、标记复制法、标记整理法。

标记-清除(Mark-Sweep)

jvm会扫描所有的对象实例,通过根搜索算法,将活跃对象进行标记,jvm再一次扫描所有对象,将未标记的对象进行清除,只有清除动作,不作任何的处理

标记清除.PNG

标记清除的优缺点

标记清除法的特点就是简单直接,速度也非常块,特别适合可回收对象不多的场景。缺点是:1、会造成不连续的内存空间即空间碎片;2、性能不稳定:内存中需要回收的对象,当内存中大量对象都是需要回收的时候,通常这些对象可能比较分散,所以清除的过程会比较耗时,这个时候清理的速度就会比较慢了。

标记复制

首先它把内存划分出三块区域,一块用于存放新创建的对象叫Eden区,另外两块则用于存放存活的对象分别叫 S1区和S2区。回收的时候会有两种情况,一种是把Eden和S1区的存活对象复制到S2区,第二种是把Eden和S2区的存活对象复制到S1区 ,也就是说S1区和S2这两块区域同时只会有一块使用,通过这种方式保证始终会有一块空白的q区域用于下次GC时存放存活的对象,而且原来的区域不需要考虑保留存活的对象,所以可以直接一次性清除所有对象,这要既简单直接同时也保证了清除的内存区域的内存连续性。jvm扫描所有对象,通过根搜索算法标记被引用的对象,之后会申请新的内存空间,将标记的对象复制到新的内存空间里,存活的对象复制完,会清空原来的内存空间,将新的内存最为jvm的对象存储空间。这样虽然解决了内存内存碎片问题,但是如果对象很多,重新申请新的内存空间会很大,在内存不足的场景下,会对jvm运行造成很大的影响

标记复制.PNG

标记复制法的优缺点

优点:标记复制法解决了标记清除法的空间碎片问题,并且采用移动存活对象的方式,每次清除针对的都是一整块内存,所以清除可回收对象的效率也比较高,但因为要移动对象所以这里会耗费一部分时间,所以标记复制法还效率还是会低于标记清除法。

不足:1、会浪费一部分空间:通过上面的图我们也不难发现,总是会有一块空闲的内存区域是利用不到的,这也造成了资源的浪费。2、存活对象多会非常耗时:因为复制移动对象的过程是比较耗时的,这个适合不仅需要移动对象本身还需要修改使用了这些对象的引用地址,所以当存活对象多的场景会非常耗时。

标记整理法

它是专门针对于存活对象多的情况下进行垃圾收集当然同时需要要避免产生空间碎片。标记整理法分为标记和整理两个阶段,标记阶段会先把存活的对象和可回收的对象标记出来;标记完之后就是进行这里了,这个阶段会把存活的对象往内存的一端移动,移动完对象后再清除存活对象边界之外的对象。

标记整理.PNG

标记整理法的优缺点:

优点:解决了标记清除法的空间碎片问题,同时也不至于像标记复制法需要空闲的内存空间,所以它非常适合存活对象多的场景。

不足:标记整理法是三种垃圾回收算法中性能最低的一种,因为标记整理法在移动对象的时候不仅需要移动对象,还要额外的维护对象的引用的地址,这个过程可能要对内存经过几次的扫描定位才能完成,做的事情越多那么必然消耗的时间也越多。

分代回收

分代收集算法是融合上述3种基础的算法思想,而产生的针对不同情况所采用不同算法的一套组合拳,根据对象存活周期的不同将内存划分为几块。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。在老年代中,因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记-清理算法或者标记-整理算法来进行回收。

分代回收.PNG