jvm-04:GC垃圾回收机制

1.1 GC概念

       GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。

1.2 GC实现机制-我们为什么要去了解GC和内存分配

       在真实工作中的项目中,时不时的会发生内存溢出、内存泄露的问题,这也是不可避免的Bug,这些潜在的Bug在某些时候会影响到项目的正常运行,如果你的项目没有合理的进行业务内存分配,将会直接影响到的项目的并发处理,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节,而了解了GC实现机制则是我们一切监控和调节的前提。

1.3 GC实现机制-Java虚拟机进行垃圾回收的地方

       说起垃圾回收的场所,了解过JVM(Java Virtual Machine Model)内存模型的朋友应该会很清楚,堆是Java虚拟机进行垃圾回收的主要场所,其次要场所是方法区。

1.4 如何断定某些对象需要进行回收处理

1.4.1 引用计数算法

       给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的,这就是引用计数算法的核心。
图例:


image.png

因此市面上的GC机制很少采用此算法来标记回收对象。缺点为:一些循环引用的对象无法进行回收。

1.4.2 可达性分析算法

       这是Java虚拟机采用的判定对象是否存活的算法。通过一系列的称为“GC Roots"的对象作为起始点,从这些结点开始向下搜索,搜索所走过的路径称为饮用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
图例:


image.png

可以看到此方法,规避了引用计数法的问题,可以更加准确的判定回收对象。目前主流的HotspotVm采用的就是可达性分析法。

1.5 如何执行垃圾回收

1.5.1 标记-清除算法

       概念介绍:用在老生代中, 先对对象进行标记,然后清楚。标记过程就是第五部分提到的标记过程。值得注意的是,使用该算法清楚过后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
图例:


image.png

红色区域是需要清理的,清理之后可见内存区域产生碎片,导致区域不连续,下次存放大对象是,若找不到足够的连续空间则会再次出发垃圾回收。所以他的缺点如下:
(1)效率问题:标记和清除过程的效率都不高;
(2)空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,碎片过多会导致大对象无法分配到足够的连续内存,从而不得不提前触发GC,甚至Stop The World。

1.5.2 复制算法

       概念介绍: 用在新生代中,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另外一块上,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可。
       这样使得每次都是对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
它的主要缺点有两个:
(1)效率问题:在对象存活率较高时,复制操作次数多,效率降低;
(2)空间问题:內存缩小了一半;需要額外空间做分配担保(老年代)
From Survivor, To Survivor使用的就是复制算法。老年代不使用这种算法。

1.5.3 标记-整理清除算法

       概念说明:由于标记清楚算法产生很多碎片,故整理算法不直接对可回收对象进行清理,而是让所有可用的对象都向一端移动。然后直接清理掉边界意外的内存。


image.png

1.5.4 分代收集算法

       GC分代的基本假设:绝大部分对象的生命周期都非常短暂,存活时间短。
        “分代收集”算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。

你可能感兴趣的:(jvm-04:GC垃圾回收机制)