精华内容
下载资源
问答
  • jdk8 cms g1gc 这篇文章是我们一年前进行的实验的跟进,比较了现实环境中不同GC算法的性能。 我们进行了相同的实验,将测试扩展为包含G1垃圾收集器,然后在不同的平台上运行了测试。 今年,我们的测试使用了以下...

    jdk8 cms g1gc

    这篇文章是我们一年前进行的实验的跟进,比较了现实环境中不同GC算法的性能。 我们进行了相同的实验,将测试扩展为包含G1垃圾收集器,然后在不同的平台上运行了测试。 今年,我们的测试使用了以下垃圾收集器:

    • -XX:+ UseParallelOldGC
    • -XX:+ UseConcMarkSweepGC
    • -XX:+ UseG1GC

    环境说明

    实验是在开箱即用的JIRA配置上进行的。 测试运行的动机很明确-Minecraft,基于Dalvik的Angry Bird和Eclipse助手, JIRA应该是其中最受欢迎的Java应用程序之一。 与替代方案相反,它是我们大多数人在日常业务中处理的更典型的代表–毕竟,到目前为止,服务器端Java EE应用程序中仍然使用最多的Java。

    同样影响我们决定的是– Atlassian的工程师在JIRA下载中进行了打包好的负载测试 因此,我们有一个基准可用于我们的配置。

    我们仔细解压缩了最新的JIRA 6.1下载文件,并将其安装在Mac OS X Mavericks上。 并运行捆绑的测试,而没有更改默认内存设置中的任何内容。 Atlassian团队非常友善,可以为我们提供服务:

    -Xms256m -Xmx768m -XX:MaxPermSize=256m

    测试以不同的通用方式使用JIRA功能-创建任务,分配任务,解决任务,搜索和发现任务等。测试的总运行时间为30分钟。

    我们使用三种不同的垃圾收集算法运行了测试–在我们的案例中使用了Parallel,CMS和G1。 每个测试均从全新的JVM引导开始,然后将存储预填充到完全相同的状态。 仅在进行准备后,我们才开始生成负载。

    结果

    在每次运行期间,我们使用-XX:+ PrintGCTimeStamps -Xloggc:/tmp/gc.log -XX:+ PrintGCDetails收集了GC日志,并在GCViewer的帮助下分析了此统计信息

    结果可以汇总如下。 请注意,所有度量单位均为毫秒:

    平行 不育系 G1
    总GC暂停时间 20930 18870 62 000
    最大GC暂停 721 64 50

    解释与结果

    第一站–并行GC( -XX:+ UseParallelOldGC )。 在完成测试所需的30分钟中,我们用并行收集器在GC暂停上花费了将近21秒。 最长的暂停时间为721毫秒。 因此,让我们以此为基准:GC周期将吞吐量减少了总运行时间的1.1% 最坏情况下的延迟是721ms

    下一位参赛者:CMS( -XX:+ UseConcMarkSweepGC )。 同样,在30分钟的测试中,GC损失了不到19秒。 在吞吐量方面,这与并行模式大致处于同一邻域。 另一方面,延迟大大改善了– 最坏情况下的延迟减少了10倍以上! 现在,GC面临的最大暂停时间仅为64毫秒

    上一个实验使用了可用的最新最明亮的GC算法– G1( -XX:+ UseG1GC )。 运行了非常相同的测试,并且在吞吐量方面,我们看到结果严重受损。 这次,我们的应用程序花费了超过一分钟的时间来等待GC完成。 与CMS的仅1%的开销相比,我们现在面临的通量影响接近3.5% 但是,如果您真的不关心吞吐量,并且想从延迟中挤出最后一点,那么-与已经不错的CMS相比,我们提高了约20% -使用G1可以看到最长的GC暂停仅花费了50ms。

    结论

    与往常一样,试图将这样的实验总结为一个结论是危险的。 因此,如果您有时间和需要的技能–一定要继续测量自己的环境,而不是采用一刀切的解决方案。

    但是,如果我敢于做出这样的结论,我会说CMS仍然是最好的“默认”选项。 G1吞吐量仍然差得多,以至于延迟通常不值得。


    翻译自: https://www.javacodegeeks.com/2013/12/g1-vs-cms-vs-parallel-gc.html

    jdk8 cms g1gc

    展开全文
  • jdk8 cms g1gc JDK 14 Early Access Build#23 ( 2019/11/13 ) 现已上市 。 此版本最值得注意的更改之一是删除了并发标记扫描垃圾收集器 。 JEP 291 [“弃用并发标记扫描(CMS)垃圾收集器”]早在2017年就使用JDK...

    jdk8 cms g1gc

    JDK 14 Early Access Build#232019/11/13现已上市 此版本最值得注意的更改之一是删除了并发标记扫描垃圾收集器 JEP 291 [“弃用并发标记扫描(CMS)垃圾收集器”]早在2017年就使用JDK 9JEP 363 [“删除并发标记扫描(CMS)垃圾收集器”) 弃用了 JDK 14的目标是完全删除CMS垃圾收集器。

    下一个屏幕快照展示了JDK 14 Early Access Build#22仍可使用CMS垃圾收集器。

    使用该JDK 14 Early Access Build#22 ,我们看到允许指定-XX:+UseConcMarkSweepGC且仅显示弃用警告:“ 选项UseConcMarkSweepGC在9.0版中已弃用,并且可能在以后的版本中删除。

    下一个屏幕快照展示了从JDK 14 Early Access Build#23开始,不能将CMS指定为垃圾收集器:

    当尝试使用-XX:+UseConcMarkSweepGC运行Java应用程序时,错误消息现在显示为:“ 忽略选项UseConcMarkSweepGC; 在“ 14.0中删除了支持

    尽管删除CMS垃圾收集器是我在JDK 14 Early Access Build#23中注意到的最大更改,但我发现其他一些更改有些有趣。 这些包括:

    翻译自: https://www.javacodegeeks.com/2019/11/jdk-14-cms-gc-is-obe.html

    jdk8 cms g1gc

    展开全文
  • 1 CMS收集器CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。这是因为CMS收集器工作时,GC工作线程与用户线程可以并发执行,以此来达到降低收集停顿时间的目的。CMS收集器仅作用于老...

    1 CMS收集器

    CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。这是因为CMS收集器工作时,GC工作线程与用户线程可以并发执行,以此来达到降低收集停顿时间的目的。

    CMS收集器仅作用于老年代的收集,是基于标记-清除算法的,它的运作过程分为4个步骤:

    初始标记(CMS initial mark)

    并发标记(CMS concurrent mark)

    重新标记(CMS remark)

    并发清除(CMS concurrent sweep)

    其中,初始标记、重新标记这两个步骤仍然需要Stop-the-world。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始阶段稍长一些,但远比并发标记的时间短。

    CMS以流水线方式拆分了收集周期,将耗时长的操作单元保持与应用线程并发执行。只将那些必需STW才能执行的操作单元单独拎出来,控制这些单元在恰当的时机运行,并能保证仅需短暂的时间就可以完成。这样,在整个收集周期内,只有两次短暂的暂停(初始标记和重新标记),达到了近似并发的目的。

    CMS收集器优点:并发收集、低停顿。

    CMS收集器缺点:

    CMS收集器对CPU资源非常敏感。

    CMS收集器无法处理浮动垃圾(Floating Garbage)。

    CMS收集器是基于标记-清除算法,该算法的缺点都有(内存碎片)。

    停顿时间是不可预期的。

    CMS收集器之所以能够做到并发,根本原因在于采用基于“标记-清除”的算法并对算法过程进行了细粒度的分解。前面篇章介绍过标记-清除算法将产生大量的内存碎片这对新生代来说是难以接受的,因此新生代的收集器并未提供CMS版本。

    另外要补充一点,JVM在暂停的时候,需要选准一个时机。由于JVM系统运行期间的复杂性,不可能做到随时暂停,因此引入了安全点的概念。

    安全点(Safepoint)

    安全点,即程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。Safepoint的选定既不能太少以至于让GC等待时间太长,也不能过于频繁以致于过分增大运行时的负荷。

    安全点的初始目的并不是让其他线程停下,而是找到一个稳定的执行状态。在这个执行状态下,Java虚拟机的堆栈不会发生变化。这么一来,垃圾回收器便能够“安全”地执行可达性分析。只要不离开这个安全点,Java虚拟机便能够在垃圾回收的同时,继续运行这段本地代码。

    程序运行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定的。“长时间执行”的最明显特征就是指令序列复用,例如方法调用、循环跳转、异常跳转等,所以具有这些功能的指令才会产生Safepoint。

    对于安全点,另一个需要考虑的问题就是如何在GC发生时让所有线程(这里不包括执行JNI调用的线程)都“跑”到最近的安全点上再停顿下来。

    两种解决方案:

    抢先式中断(Preemptive Suspension)

    抢先式中断不需要线程的执行代码主动去配合,在GC发生时,首先把所有线程全部中断,如果发现有线程中断的地方不在安全点上,就恢复线程,让它“跑”到安全点上。现在几乎没有虚拟机采用这种方式来暂停线程从而响应GC事件。

    主动式中断(Voluntary Suspension)

    主动式中断的思想是当GC需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。轮询标志的地方和安全点是重合的,另外再加上创建对象需要分配内存的地方。

    安全区域

    指在一段代码片段中,引用关系不会发生变化。在这个区域中任意地方开始GC都是安全的。也可以把Safe Region看作是被扩展了的Safepoint。

    2 G1收集器

    G1重新定义了堆空间,打破了原有的分代模型,将堆划分为一个个区域。这么做的目的是在进行收集时不必在全堆范围内进行,这是它最显著的特点。区域划分的好处就是带来了停顿时间可预测的收集模型:用户可以指定收集操作在多长时间内完成。即G1提供了接近实时的收集特性。G1 的主要关注点在于达到可控的停顿时间,在这个基础上尽可能提高吞吐量。

    G1 使用了停顿预测模型来满足用户指定的停顿时间目标,并基于目标来选择进行垃圾回收的区块数量。G1 采用增量回收的方式,每次回收一些区块,而不是整堆回收。要清楚 G1 不是一个实时收集器(只是接近实时),它会尽力满足我们的停顿时间要求,但也不是绝对的,它基于之前垃圾收集的数据统计,估计出在用户指定的停顿时间内能收集多少个区块。

    G1与CMS的特征对比如下:

    特征

    G1

    CMS

    并发和分代

    最大化释放堆内存

    低延时

    吞吐量

    压实

    可预测性

    新生代和老年代的物理隔离

    G1具备如下特点:

    并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-the-world停顿的时间,部分其他收集器原来需要停顿Java线程执行的GC操作,G1收集器仍然可以通过并发的方式让Java程序继续运行。

    分代收集

    空间整合:与CMS的标记-清除算法不同,G1从整体来看是基于标记-整理算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的。但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。

    可预测的停顿:这是G1相对于CMS的一个优势,降低停顿时间是G1和CMS共同的关注点。

    在G1之前的其他收集器进行收集的范围都是整个新生代或者老年代,而G1不再是这样。在堆的结构设计时,G1打破了以往将收集范围固定在新生代或老年代的模式,G1收集器将整个Java堆划分为多个大小相等的独立区域(Region)。Region是一块地址连续的内存空间,G1模块的组成如下图所示:

    3837d373fa5e299c79714e3611738e24.png

    虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。Region的大小是一致的,数值是在1M到32M字节之间的一个2的幂值数,JVM会尽量划分2048个左右、同等大小的Region,这一点可以参看如下源码。其实这个数字既可以手动调整,G1也会根据堆大小自动进行调整。

    #ifndef SHARE_VM_GC_G1_HEAPREGIONBOUNDS_HPP

    #define SHARE_VM_GC_G1_HEAPREGIONBOUNDS_HPP

    #include "memory/allocation.hpp"

    class HeapRegionBounds : public AllStatic {

    private:

    // Minimum region size; we won't go lower than that.

    // We might want to decrease this in the future, to deal with small

    // heaps a bit more efficiently.

    static const size_t MIN_REGION_SIZE = 1024 * 1024;

    // Maximum region size; we don't go higher than that. There's a good

    // reason for having an upper bound. We don't want regions to get too

    // large, otherwise cleanup's effectiveness would decrease as there

    // will be fewer opportunities to find totally empty regions after

    // marking.

    static const size_t MAX_REGION_SIZE = 32 * 1024 * 1024;

    // The automatic region size calculation will try to have around this

    // many regions in the heap (based on the min heap size).

    static const size_t TARGET_REGION_NUMBER = 2048;

    public:

    static inline size_t min_size();

    static inline size_t max_size();

    static inline size_t target_number();

    };

    #endif // SHARE_VM_GC_G1_HEAPREGIONBOUNDS_HPP

    复制

    G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个Java堆中进行全区域的垃圾收集。G1会通过一个合理的计算模型,计算出每个Region的收集成本并量化,这样一来,收集器在给定了“停顿”时间限制的情况下,总是能选择一组恰当的Regions作为收集目标,让其收集开销满足这个限制条件,以此达到实时收集的目的。

    对于打算从CMS或者ParallelOld收集器迁移过来的应用,按照官方 的建议,如果发现符合如下特征,可以考虑更换成G1收集器以追求更佳性能:

    实时数据占用了超过半数的堆空间;

    对象分配率或“晋升”的速度变化明显;

    期望消除耗时较长的GC或停顿(超过0.5——1秒)。

    原文如下:

    Applications running today with either the CMS or the ParallelOld garbage collector would benefit switching to G1 if the application has one or more of the following traits.

    More than 50% of the Java heap is occupied with live data.

    The rate of object allocation rate or promotion varies significantly.

    Undesired long garbage collection or compaction pauses (longer than 0.5 to 1 second)

    G1收集的运作过程大致如下:

    初始标记(Initial Marking):仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程,但耗时很短。

    并发标记(Concurrent Marking):是从GC Roots开始堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行。

    最终标记(Final Marking):是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行。

    筛选回收(Live Data Counting and Evacuation):首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。这个阶段也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。

    全局变量和栈中引用的对象是可以列入根集合的,这样在寻找垃圾时,就可以从根集合出发扫描堆空间。在G1中,引入了一种新的能加入根集合的类型,就是记忆集(Remembered Set)。Remembered Sets(也叫RSets)用来跟踪对象引用。G1的很多开源都是源自Remembered Set,例如,它通常约占Heap大小的20%或更高。并且,我们进行对象复制的时候,因为需要扫描和更改Card Table的信息,这个速度影响了复制的速度,进而影响暂停时间。

    4761c83630758222b88e324d44e72c21.png

    G1 比 ParallelOld 和 CMS 会需要更多的内存消耗,那是因为有部分内存消耗于簿记(accounting)上,如以下两个数据结构:

    Remembered Sets:每个区块都有一个 RSet,用于记录进入该区块的对象引用(如区块 A 中的对象引用了区块 B,区块 B 的 Rset 需要记录这个信息),它用于实现收集过程的并行化以及使得区块能进行独立收集。

    Collection Sets:将要被回收的区块集合。GC 时,在这些区块中的对象会被复制到其他区块中,总体上 Collection Sets 消耗的内存小于 1%。

    卡表(Card Table)

    有个场景,老年代的对象可能引用新生代的对象,那标记存活对象的时候,需要扫描老年代中的所有对象。因为该对象拥有对新生代对象的引用,那么这个引用也会被称为GC Roots。那不是得又做全堆扫描?成本太高了吧。

    HotSpot给出的解决方案是一项叫做卡表(Card Table)的技术。该技术将整个堆划分为一个个大小为512字节的卡,并且维护一个卡表,用来存储每张卡的一个标识位。这个标识位代表对应的卡是否可能存有指向新生代对象的引用。如果可能存在,那么我们就认为这张卡是脏的。

    在进行Minor GC的时候,我们便可以不用扫描整个老年代,而是在卡表中寻找脏卡,并将脏卡中的对象加入到Minor GC的GC Roots里。当完成所有脏卡的扫描之后,Java虚拟机便会将所有脏卡的标识位清零。

    想要保证每个可能有指向新生代对象引用的卡都被标记为脏卡,那么Java虚拟机需要截获每个引用型实例变量的写操作,并作出对应的写标识位操作。

    卡表能用于减少老年代的全堆空间扫描,这能很大的提升GC效率。

    我们可以看下官方文档对G1的展望(这段英文描述比较简单,我就不翻译了):

    Future:

    G1 is planned as the long term replacement for the Concurrent Mark-Sweep Collector (CMS). Comparing G1 with CMS, there are differences that make G1 a better solution. One difference is that G1 is a compacting collector. G1 compacts sufficiently to completely avoid the use of fine-grained free lists for allocation, and instead relies on regions. This considerably simplifies parts of the collector, and mostly eliminates potential fragmentation issues. Also, G1 offers more predictable garbage collection pauses than the CMS collector, and allows users to specify desired pause targets.

    展开全文
  • G1的定位是取代CMS,相比CMSG1能够更有效的避免碎片化,同时可以让用户指定预期的停顿时间。G1的机制G1同样是分代的垃圾回收,但是不同的是G1把整个堆分成了大小相等的块(称为region),每个region可以被分配为不同...

    简介

    G1(Garbage-First)垃圾回收器是在jdk7版本开始被引进的,它的特性在于能够尽可能的满足用户对停顿时间的要求同时还保持较高的吞吐。G1的定位是取代CMS,相比CMS,G1能够更有效的避免碎片化,同时可以让用户指定预期的停顿时间。

    G1的机制

    G1同样是分代的垃圾回收,但是不同的是G1把整个堆分成了大小相等的块(称为region),每个region可以被分配为不同的角色(young、eden、old等等),这意味着不同代的内存大小是不固定的,可以灵活地调整。

    G1会在jvm启动时确定region size(最小1M,最大32M),通常G1会尽量把堆分为2048个相同大小的region,具体的region size由此计算,也可以在jvm参数里显示指定。不同的region会被分配到不同的逻辑角色,比如eden/old,同一个逻辑角色的不同region也不一定是连续的。

    G1的运行机制与CMS类似,G1会进行并发的全局标记来判断对象的存活与否,在标记结束后,G1就能得知哪些region中的垃圾最多,然后就先回收这部分region,这就是G1的名字的由来。G1采用了一个停顿时间预测的模型来尽可能满足用户指定的停顿时间,根据用户指定的停顿时间来选择要回收哪些region。

    G1在进行垃圾回收时采用的是复制算法,G1会把各个region中残留的存活对象复制到单独的region中,这样在回收过程中就完成了内存的整理。为了降低复制过程中停顿的时间,整个复制过程是并行的,而CMS并不会进行内存整理,ParallelOld则是会直接整理整个堆,显然会明显增加停顿时间。

    G1的各个阶段

    young gc

    发生young gc时,存活的对象被复制到survivor区,如果对象的年龄超过阈值,那么会把它晋升到old区。整个young gc过程中是STW的,同时也会重新计算出下一次GC时的eden区和survivor区的大小,计算过程中也会考虑用户指定的目标停顿时间。因为region的设计,要调整各个分区的大小实际上非常容易。

    concurrent marking cycle

    并发标记是G1中的一个重要阶段,这个阶段包括若干个步骤,通过并发标记来收集各个region的使用情况等信息,协助达到用户指定的停顿时间。

    initial mark(STW)

    这一步是和young gc一起顺带着执行的,首先标记出gc roots直接可达的对象,

    root region scanning

    young gc过后,survivor中的对象都被标记为root region,这时扫描由survivor区直接可达的old区并标记。这一阶段必须在新一轮的young gc前执行完毕。如果这时又需要young gc,那么会等待扫描完成才会进行。

    concurrent marking

    扫描整个堆,标记存活的对象,整个阶段是与应用程序并行的,可能被young gc打断。这个阶段下会不断从扫描栈取出引用,递归地扫描整个堆里的对象图。每扫描到一个对象就会对其标记,并将其字段压入扫描栈。重复扫描过程直到扫描栈清空。过程中还会扫描SATB write barrier所记录下的引用。

    remark(STW)

    在完成并发标记后,每个Java线程还会有一些剩下的SATB write barrier记录的引用尚未处理。这个阶段就负责把剩下的引用处理完。同时这个阶段也进行弱引用处理(reference processing)。注意这个暂停与CMS的remark有一个本质上的区别,那就是这个暂停只需要扫描SATB buffer,而CMS的remark需要重新扫描mod-union table里的dirty card外加整个根集合,而此时整个young gen(不管对象死活)都会被当作根集合的一部分,因而CMS remark有可能会非常慢。

    cleanup(STW)

    这阶段会清理各个region,同时更新Rset,如果有空的region就把它释放掉。

    copying(STW)

    把存活的对象拷贝到新的region。

    G1的老年代回收总结

    concurrent mark阶段

    存活对象的信息是在运行时并发地计算的

    在复制阶段,G1会根据每个region内存活对象的信息确定哪些region优先被回收

    没有类似CMS中的sweep过程(因为是直接evacuate整个region)

    remark阶段

    SATB算法,(据说)会比CMS更快

    空的region会被直接回收

    cleanup/copying阶段

    young和old区同时进行回收

    会根据情况选择特定的old区region进行回收

    混合GC

    在经历了一个完整的标记周期过后,G1会在下一次young gc的时刻转换成混合gc,混合gc下,G1可能会把一部分old区的region加入Cset中,利用young gc的算法清理一部分old region。当G1回收了足够多的old region,又会重新回到young gc,直到下一次并发标记周期完成。

    总结

    G1的目标是要代替CMS,它把整个堆空间划分成了不同的region来进行管理,使得分配和回收更加灵活。G1的主要活动包括young gc、mixed gc以及并发标记,它会根据用户指定的目标停顿时间来决定要对哪些内存区域进行回收。

    Remembered Sets和Collection Sets

    RSet用于记录指向某个region的引用,每个region对应一个RSet,这个数据结构里记录了哪些其他region包含了指向这个region的对象的引用。CSet记录了GC过程中会被回收的region,CSet中存活的对象在GC过程中都会被复制到新的空的region。Rset和Cset都是为了帮助GC而产生的额外的数据结构。

    G1的heap与HotSpot VM的其它GC一样有一个覆盖整个heap的card table。逻辑上说,G1的RSet是每个region有一份。这个RSet记录的是从别的region指向该region的card。所以这是一种“points-into”的Remembered Set。用card table实现的Remembered Set通常是points-out的,也就是说card table要记录的是从它覆盖的范围出发指向别的范围的指针。以分代式GC的card table为例,要记录old -> young的跨代指针,被标记的card是old gen范围内的。

    G1则是在points-out的card table之上再加了一层结构来构成points-into RSet:每个region会记录下到底哪些别的region有指向自己的指针,而这些指针分别在哪些card的范围内。这个RSet其实是一个hash table,key是别的region的起始地址,value是一个集合,里面的元素是card table的index。

    SATB算法

    G1在concurrent mark阶段使用了SATB算法来避免对象的漏标记,而SATB是snapshot at the beginning的缩写。简单来说,SATB的思路就是认定在GC开始时存活的对象就是存活的,此时整个堆内的所有对象形成一个快照(snapshot);同时认定在GC过程中新产生的对象也都是存活的,而剩下的不可达的对象则都是垃圾了。

    而G1是如何确定哪些对象是在GC开始后新产生的呢,这依赖两个指针:prevTAMS和nextTAMS。TAMS是top at mark start的缩写,这里就要再介绍一下region的几个指针了:

    d2faf66787c84ea13fc82bbe7b9d7abe.png

    [bottom, top)部分为该region中已经使用的部分

    [top, end)部分为该region中未使用的部分

    在每次concurrent mark开始时,将当前top赋值给nextTAMS,那么在concurrent mark过程中,该region上新分配的对象都落在nextTAMS和top之间,G1保证这部分对象都不会被漏标,默认都是存活的。

    当concurrent mark结束时,将当前的nextTAMS赋值给prevTAMS,同时根据mark的结果,将[bottom, prevTAMS]之间的对象的存活信息保存为一个bitmap,后续就可以通过这个bitmap确定对应的对象是否存活了。

    由于对象的存活标记是和应用程序并发执行的,应用程序完全有可能在标记过程中修改对象的引用,所以为了避免漏标记,G1使用了write barrier。write barrier是指在"对引用类型字段赋值"这个动作前后的一个拦截,可以在赋值的前后进行额外的工作。在赋值前的部分的write barrier叫做pre-write barrier,在赋值后的则叫做post-write barrier,G1则使用了pre-write barrier。为了避免漏标,G1会在每次引用赋值前把这个引用指向的旧的值也进行递归地标记,并默认其为存活,这样就不会漏掉任何一个snapshot中的对象了。当这个旧的值实际上不再是存活对象时,它实际上也就成为了浮动垃圾,只能留到下一轮垃圾回收了。

    可以看出,上面提到的barrier中的工作实际上都是在应用程序的线程中完成的。为了尽量减少write barrier对性能的影响,G1将一部分原本要在barrier里做的事情挪到别的线程上并发执行。实现这种分离的方式就是通过logging形式的write barrier:应用程序只在barrier里把要做的事情的信息记(log)到一个队列里,然后另外的线程从队列里取出信息批量完成剩余的动作。

    以SATB write barrier为例,每个Java线程有一个独立的、定长的SATBMarkQueue,应用程序线程在barrier里只把old_value压入该队列中。一个队列满了之后,它就会被加到全局的SATB队列集合SATBMarkQueueSet里等待处理,然后给对应的Java线程换一个新的、干净的队列继续执行下去。

    concurrent mark会定期检查全局SATB队列集合的大小。当全局集合中队列数量超过一定阈值后,concurrent marker就会处理集合里的所有队列:把队列里记录的每个oop都标记上,并将其引用字段压到标记栈(marking stack)上等后面做进一步标记。

    展开全文
  • 一.CMS详解CMS介绍CMS是用于分代垃圾回收算法,老年代中。可使用户线程和GC线程同时执行的垃圾回收器。可与Serial收集器和Parallel New收集器搭配使用。CMS牺牲了系统的吞吐量来追求收集速度,适合追求垃圾收集速度...
  • 可预测的停顿:这是G1相对于CMS的一个优势,降低停顿时间是G1CMS共同的关注点。 总结 随着JVM的发展,ORACLE官方推出的JDK11又有了新算法ZGC,它对内存碎片的整理更加优化,回收暂停时间也更加缩短,具体细节本人...
  • JVM(垃圾回收)CMS G1

    2019-04-09 17:43:46
    降低停顿时间是G1CMS共同的关注点 ,G1除了追求低停顿外,还能 建立可预测的停顿时间模型 , 能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。 在使用G1收集器时,...
  • 堆内存常见的分配策略针对的是Serial 加 Serial Old 客户端默认收集器组合下的内存分配和回收策略 经典的垃圾收集器 CMS 收集器CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的垃圾收集器。...
  • CMS 优点:低停顿,并发标记 ...CMS G1相同点 初始标记 并发标记 CMS G1 不同点 重新标记 VS 最终标记 并发清理 VS 筛选回收 CMS:以获取最短回收停顿时间为目标的收集器,基于并发...
  • CMS & G1

    2020-11-09 19:34:48
    G1CMS的区别 参考:CMS收集器和G1收集器优缺点 什么是CMS CMS全称ConcurrentMarkSweep,是一款并发的、使用标记-清除算法的垃圾回收器, 如果老年代使用CMS垃圾回收器,需要添加虚拟机参数-"XX:+...
  • CMSG1的区别是我最近在面试过程中经常被问到的一个问题,虽然能答出几点出来,但是自己并不太满意,网上关于两者的对比也没有特别完善的文章,于是打算记录下这篇文章 首先我把答案给出来,然后再去分析为什么会...
  • CMSG1

    2020-09-12 21:52:01
    CMS 1、目标 CMS以获取最短回收停顿时间为目标。 2、采用的算法 CMS采用的算法是:标记-清除。 3、概念 Stop The Word:虚拟机停顿正在执行的任务,即停顿用户线程。 4、CMS收集过程 ①初始标记:Stop The ...
  • CMSG1

    2020-07-04 11:33:14
    其实在JDK11后 8G以上内存99%的场景下 G1都比CMS表现更为优秀。 G1内存模型对比CMS和之前的垃圾收集器有了很大的改变。这无疑是惊艳的。 从上图可以看出G1把堆内存划分为若干个区域(Regi...
  • CMSG1的区别

    2020-05-14 17:39:09
    CMSG1的区别
  • CMSG1详解

    千次阅读 2020-04-16 19:31:55
    1.G1是包括年轻代和年老代的GC 2.CMS是年老代GC 3.二者在某些时候都需要FullGC(serial old GC)的辅助 1 CMS收集器 CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。这是因为...
  • CMSG1

    2019-02-19 15:18:44
    Concurrent Mark Sweep收集器运行示意图 初始标记阶段:标记一下GC Roots能直接关联到的对象,速度很快 并发标记阶段:进行GC Roots Tracing 重新标记阶段:修正并发标记期间因为用户...CMS收集器对CPU资源非...
  • CMSG1比较

    2020-09-07 12:52:46
    一、CMS CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。这是因为CMS收集器工作时,GC工作线程与用户线程可以并发执行,以此来达到降低收集停顿时间的目的。 CMS收集器仅作用于老...
  • CMSG1算法

    2020-03-31 23:54:13
    CMS过程: 1.初始标记(stw) 2.并行标记(产生漏标) 3.重新标记(stw) 4.并行清除 (产生浮动垃圾 和 碎片) G1: YGC+MixGC + FullGC(Serial Old) MixGC过程: 1.初始标记(stw) 2.并行标记(产生漏标) 3.重新...
  • *CMSG1

    2020-05-22 19:13:04
    CMS CMS(concurrent mark sweep) 是一种以获取最短回收停顿时间为目标的垃圾收集器。这是因为CMS在工作时可以与用户线程并发执行,以此来降低停顿时间。 CMS用于老年代回收,使用标记-清除算法。 为什么不采用...
  • CMSG1垃圾收集器

    2020-05-06 16:45:03
    CMS收集器 G1收集器
  • CMS回收垃圾的4个阶段CMS的总结和优缺点G1回收器特点G1回收垃圾的4个阶段什么情况下应该考虑使用G1G1设置参数CMS回收垃圾的4个阶段初始标记并发标记重新标记并发清理初始标记阶段:会让线程全部停止,也就是 Stop ...
  • JVM CMSG1执行过程

    2020-11-05 21:52:51
    首先我们先了解一下CMSG1是做什么的? 都是垃圾回收器 相同的地方:都是并发执行(垃圾收集线程与用户线程同步执行) 不同的地方: 关注点:CMS尽可能缩短垃圾收集时用户线程的停顿时间。G1实现可预期及可配置...
  • 3.CMSG1的异同

    2020-03-14 20:44:42
    3.CMSG1的异同
  • 说说CMSG1垃圾收集器1 CMS收集器1.1 CMS收集器的过程1.2 CMS优点1.3 CMS缺点2 G1收集器2.1 G1的优势2.2 G1垃圾收集过程 1 CMS收集器 CMS收集器是以获取最短回收停顿时间为目标的老年代收集器, 所以非常适合希望...
  • CMSG1的最终标记

    2020-06-29 20:03:59
    问题1:CMSG1的重新标记,最终标记的目的是什么? 工作流程上来看,CMS的重新标记,和G1的最终标记之前,都是并发标记!并发标记就是,标记程序和用户程序同时执行!既然是同时运行,用户程序就可能修改对象的引用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,098
精华内容 839
关键字:

cmsg1