jvm完整的gc流程,深入理解jvm&g1 gc
目录
GC简介什么是GC?为什么要学习GCGC垃圾对象判定、引用计数法、可达性分析方法、常用GC算法分析、标记清除、标记复制、标记排序、生成回收章节面试分析
GC简介
00-1010 GC(垃圾收集)称为垃圾收集,是利用一定的算法在内存中收集垃圾对象的一种动作。比如java中的垃圾回收,会遍历内存中的对象,对幸存的对象进行标记,未标记的对象可以视为垃圾对象,然后基于特定的算法进行回收。
00-1010深入了解GC的工作机制,可以帮助你写出更好的Java应用,提高开发效率。也是大规模应用开发的先决条件。
何为GC
00-1010该算法为每个对象设置一个引用计数器。每当有对这个对象的引用时,计数器就加1,反之,每当引用无效时,计数器就减1。也就是通过计数来判断一个对象是不是垃圾。当一个对象的引用计数器值为0时,意味着该对象在被使用和JVM中的GC被触发时不会被回收。如图所示:
其中包括:
绿色的云是内存中的根对象,它表示程序中正在使用的对象。蓝色圆圈是内存中的活动对象,其中的数字表示其引用计数。灰色圆圈是在内存中没有活动对象引用的对象,表示非活动对象。对于引用计数法,实现简单,垃圾对应也容易识别。但是,也有一些缺陷。我们的每个对象都需要有一个单独的对象引用计数器,并且这个计数器的值必须经常更新。还有最严重的循环引用问题,如图:
其中红色对象实际上是应用程序不使用的垃圾。但是由于引用计数的限制,内存泄漏依然存在。当然,有一些方法可以处理这种情况,比如“‘弱’引用或者使用其他算法来检查循环引用。
00-1010该算法的核心思想是以一系列“GC根”对象为起点进行搜索,搜索所走的路径称为“引用链”。当一个对象连接到GC根而没有任何引用链时,证明这个对象是可以回收的。否则,证明这个对象是有用的,不是垃圾。如图所示:
当GC遍历内存中的整个对象图时,它必须首先确定根对象。什么样的对象可以作为根对象?GC规范表明根对象可以是:
1)1)Java虚拟机堆栈中的引用对象;2)本地方法栈中被JNI引用的对象(一般就是原生方法);3)方法区中类静态常量的引用对象;4)方法区域中常量的引用对象。
根对象确定后,从根对象开始依赖搜索,所有可访问对象都被认为是活对象,然后进行标记。
注意:标记可到达的对象需要挂起所有应用程序线程,以确定对象的引用关系。暂停时间与堆内存大小和对象总数没有直接关系,而是由活动对象的数量决定。
为何要学习GC
00-1010标记扫描算法分为“标记”和“清除”两个阶段。它首先标记内存中所有不需要回收的对象,然后从内存中清除所有未标记的对象。如图所示:
标记算法的优点是简单直接,缺点是效率低,可能产生大量不连续的碎片。因为标记和清除过程都需要扫描内存空间(第一次:标记活的对象,第二次:清除未标记的对象),所以效率很低。更有甚者,清理后产生的大量不连续内存碎片无法满足更大对象的存储需求,可能再次触发垃圾回收。所以这种垃圾收集算法应该适用于对象存活率高的内存区域(比如JVM中的老年)。
00-1010标记复制算法将内存分成两个大小相同的块。当这个块用完了,它就把当前活的对象复制到另一个块,然后一次性清空当前块。如图所示:
“标记-复制”算法的缺点很明显,即内存空间利用率低,适用于那些对象生命周期短、回收频率高的内存区域(如JVM中的年轻一代)。
结合ldqu的00-1010标记-扫描-压缩算法
o;标记-清除和复制两个算法的优点。第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把存活对象压缩复制到堆的其中一块空间中,按顺序排放。第三阶段清理掉存活边界以外的全部内存空间。如图所示:
系统GC时每次执行清除(sweeping)操作, JVM 都必须保证不可达对象占用的内存能被回收然后重用。内存是被回收了,但这有可能会产生大量的内存碎片(类似于磁盘碎片), 进而引发两个问题:
对象创建时,执行写入操作越来越耗时, 因为寻找一块足够大的空闲内存会变得更加麻烦。对象创建时, JVM需要在连续的内存块中为对象分配内存。如果碎片问题很严重, 直至没有空闲片段能存放新创建的对象,就会发生内存分配错误(allocation error)。为了解决碎片问题,JVM在启动GC执行垃圾收集的过程中, 不仅仅是标记和清除, 还需要执行 内存碎片整理。这个过程会让所有可达对象(reachable objects)进行依次移动,进而可以消除(或减少)内存碎片,并为新对象提供更大并且连续的内存空间。
标记整理算法避免了标记-清除的碎片问题,同时也避免了复制算法的空间问题,由于需要向一侧移动等一系列操作,其效率相对低一些,但对内存空间管理上十分优异。适用于那些生命周期长、回收频率低,但注重回收一次内存空间得到足够释放的场景。
分代回收
我们知道垃圾收集要停止整个应用程序的运行,那么假如这个收集过程需要的时间很长,就会对应用程序产生很大性能问题,如何解决这个问题呢?通过实验发现内存中的对象通常可以将其分为两大类:
存活时间较短(这样的对象比较多)。存活时间较长(这样的对象比较少)。基于对如上问题的分析,科学家提出了分代回收思路,将VM中内存分为年轻代(Young Generation)和老年代(Old Generation-老年代有时候也称为年老区(Tenured)。例如:
Young区存储的就是那些生命周期短,使用一两次就不再使用的对象,回收一次基本上该区域十之有八的对象全部被回收清理掉,因此Young区采用的垃圾回收算法也就是标记-复制算法。Old区存储的是那些生命周期长,经过多次回收后仍然存活的对象,就把它们放到Old区中,Old区一般不去判断这些对象的可达性,直到Old区不够用为止,再进行一次统一的回收,释放出足够的连续的内存空间。所以我们选择标记-清除或标记-整理算法进行垃圾收集。
在分代回收过程中,垃圾收集事件(Garbage Collection events)通常分为:
Minor GC (小型GC):年轻代GC事件,(新对象)分配频率越高, Minor GC 的频率就越高。Major GC (大型GC): 老年代GC事件。Full GC (完全GC):整个堆的GC事件。说明:一般情况下可以将Major GC与Full GC看成是同一种GC。
章节面试分析
1)何为GC?2)为什么要GC?3)如何判定内存中的对象是否为垃圾对象?4)常用垃圾回收算法有哪些?
到此这篇关于JVM中的GC初识的文章就介绍到这了,更多相关初识JVM中的GC内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。