CMS Collector and G1 Collector
Understanding the CMS Collector
CMS has three basic operations:
- CMS collects the young generation (stopping all application threads).
- CMS runs a concurrent cycle to clean data out of the old generation.
- If necessary, CMS performs a full GC.
concurrent cycle
- The JVM starts a concurrent cycle based on the occupancy of the heap. When it is
sufficiently full, the JVM starts background threads that cycle through the heap and
remove objects. - The concurrent cycle starts with an initial mark phase, which stops all the application
threads.This phase is responsible for finding all the GC root objects in the heap. - The next phase is the mark phase, and it does not stop the application threads.Since it is just a
marking phase, it hasn’t done anything to the heap occupancy, and so no data is shown
about that. - Next comes a preclean phase, which also runs concurrently with the application threads:
- The next phase is a remark phase, but it involves several operations:
- Next comes another concurrent phase—the sweep phase:
- Next comes the concurrent reset phase:
concurrent mode failure:
- When a young collection occurs and there isn’t enough room in the old generation to
hold all the objects that are expected to be promoted, CMS executes what is essentially
a full GC. All application threads are stopped, and the old generation is cleaned of any
dead objects, reducing its occupancy to 1,366 MB—an operation which kept the application
threads paused for a full 5.6 seconds. That operation is single-threaded, which is one reason it takes so long (and one reason why concurrent mode failures are worse as
the heap grows). - The second problem occurs when there is enough room in the old generation to hold
the promoted objects, but the free space is fragmented and so the promotion fails:- As a result, in the middle of the young collection (when all threads were already stopped),
CMS collected and compacted the entire old generation. The good news is that
with the heap compacted, fragmentation issues have been solved (at least for a while).
But that came with a hefty 28-second pause time. This time is much longer than when
CMS had a concurrent mode failure because the entire heap was compacted; the concurrent
mode failure simply freed objects in the heap. The heap at this point appears as
it did at the end of the throughput collector’s full GC (Figure 6-2): the young generation
is completely empty, and the old generation has been compacted. - This occurs when permgen has filled up and needs to be collected; notice that the size
of the CMS Perm space has dropped. In Java 8, this can also occur if the metaspace needs
to be resized. By default, CMS does not collect permgen (or the metaspace), so if it fills
up, a full GC is needed to discard any unreferenced classes.
- As a result, in the middle of the young collection (when all threads were already stopped),
summary
- CMS has several GC operations, but the expected operations are
minor GCs and concurrent cycles. - Concurrent mode failures and promotion failures in CMS are
quite expensive; CMS should be tuned to avoid these as much as
possible. - By default, CMS does not collect permgen.
Understanding the G1 Collector
- G1 is a concurrent collector that operates on discrete regions within the heap. Each
region (there are by default around 2,048 of them) can belong to either the old or new
generation, and the generational regions need not be contiguous. The idea behind having
regions in the old generation is that when the concurrent background threads look
for unreferenced objects, some regions will contain more garbage than other regions.
The actual collection of a region still requires that application threads be stopped, but
G1 can focus on the regions that are mostly garbage and only spend a little bit of time
emptying those regions. This approach—clearing out only the mostly garbage regions
—is what gives G1 its name: Garbage First. - That doesn’t apply to the regions in the young generation: during a young GC, the entire
young generation is either freed or promoted (to a survivor space or to the old generation).
Still, the young generation is defined in terms of regions, in part because it makes
resizing the generations much easier if the regions are predefined.
G1 has four main operations:- A young collection
- A background, concurrent cycle
- A mixed collection
- If necessary, a full GC
young collection
- The G1 young collection is triggered when eden fills up (in this case, after filling four
regions). After the collection, there are no regions assigned to eden, since it is empty.
There is at least one region assigned to the survivor space (partially filled in this example),
and some data has moved into the old generation. - 23.430: [GC pause (young), 0.23094400 secs]
…
[Eden: 1286M(1286M)->0B(1212M)
Survivors: 78M->152M Heap: 1454M(4096M)->242M(4096M)]
[Times: user=0.85 sys=0.05, real=0.23 secs] - Collection of the young generation took 0.23 seconds of real time, during which the GC
threads consumed 0.85 seconds of CPU time. 1,286 MB of objects were moved out of
eden (which was resized to 1,212 MB); 74 MB of that was moved to the survivor space
(it increased in size from 78 M to 152 MB) and the rest were freed. We know they were
freed by observing that the total heap occupancy decreased by 1,212 MB. In the general
case, some objects from the survivor space might have been moved to the old generation,
and if the survivor space were full, some objects from eden would have been promoted
directly to the old generation—in those cases, the size of the old generation would
increase.
concurrent G1 cycle
- Finally, notice that the old generation (consisting of the regions marked with an O or
an X) is actually more occupied after the cycle has completed. That’s because the young
generation collections that occurred during the marking cycle promoted data into the old generation. In addition, the marking cycle doesn’t actually free any data in the old
generation: it merely identifies regions that are mostly garbage. Data from those regions
is freed in a later cycle. - The G1 concurrent cycle has several phases, some of which stop all application threads
and some of which do not. The first phase is an initial-mark phase. That phase stops all
application threads—partly because it also executes a young collection:- As in a regular young collection, the application threads were stopped (for 0.28 seconds),
and the young generation was emptied (71 MB of data was moved from the young
generation to the old generation). The initial-mark output announces that the background
concurrent cycle has begun. Since the initial mark phase also requires all application
threads to be stopped, G1 takes advantage of the young GC cycle to do that
work. The impact of adding the initial mark phase to the young GC wasn’t that large: it
used 20% more CPU cycles than the previous collection, even though the pause was
only slightly longer. (Fortunately, there were spare CPU cycles on the machine for the
parallel G1 threads, or the pause would have been longer.)
- As in a regular young collection, the application threads were stopped (for 0.28 seconds),
- Next, G1 scans the root region:
- 350.994: [GC pause (young)
351.093: [GC concurrent-root-region-scan-end, 0.6100090]
351.093: [GC concurrent-mark-start],
0.37559600 secs] - This takes 0.58 seconds, but it doesn’t stop the application threads; it only uses the
background threads. However, this phase cannot be interrupted by a young collection,
so having available CPU cycles for those background threads is crucial. If the young
generation happens to fill up during the root region scanning, the young collection
(which has stopped all the application threads) must wait for the root scanning to complete.
In effect, this means a longer-than-usual pause to collect the young generation. - The GC pause here starts before the end of the root region scanning, which (along with
the interleaved output) indicates that it was waiting. The timestamps show that application
threads waited about 100 ms—which is why the duration of the young GC pause
is about 100 ms longer than the average duration of other pauses in this log.
- 350.994: [GC pause (young)
- After the root region scanning, G1 enters a concurrent marking phase. This happens
completely in the background; a message is printed when it starts and ends:- 111.382: [GC concurrent-mark-start]
….
120.905: [GC concurrent-mark-end, 9.5225160 sec]
- 111.382: [GC concurrent-mark-start]
- Concurrent marking can be interrupted, so young collections may occur during this
phase. The marking phase is followed by a remarking phase and a normal cleanup phase:- 120.910: [GC remark 120.959:
[GC ref-PRC, 0.0000890 secs], 0.0718990 secs]
[Times: user=0.23 sys=0.01, real=0.08 secs]
120.985: [GC cleanup 3510M->3434M(4096M), 0.0111040 secs]
[Times: user=0.04 sys=0.00, real=0.01 secs]
- 120.910: [GC remark 120.959:
- These phases stop the application threads, though usually for a quite short time. Next
there is an additional cleanup phase that happens concurrently:- 120.996: [GC concurrent-cleanup-start]
120.996: [GC concurrent-cleanup-end, 0.0004520]
- 120.996: [GC concurrent-cleanup-start]
- And with that, the normal G1 cycle is complete—insofar as finding the garbage goes, at
least. But very little has actually been freed yet. A little memory was reclaimed in the
cleanup phase, but all G1 has really done at this point is to identify old regions that are
mostly garbage and can be reclaimed (the ones marked with an X in Figure 6-7).
mixed GCs.
- Now G1 executes a series of mixed GCs. They are called mixed because they perform
the normal young collection, but they also collect some number of the marked regions
from the background scan. - As is usual for a young collection, G1 has completely emptied eden and adjusted the
survivor spaces. Additionally, two of the marked regions have been collected. Those
regions were known to contain mostly garbage, and so a large part of them was freed. Any live data in those regions was moved to another region (just as live data was moved
from the young generation into regions in the old generation). This is why G1 ends up
with a fragmented heap less often than CMS—moving the objects like this is compacting
the heap as G1 goes along. - 79.826: [GC pause (mixed), 0.26161600 secs]
….
[Eden: 1222M(1222M)->0B(1220M)
Survivors: 142M->144M Heap: 3200M(4096M)->1964M(4096M)]
[Times: user=1.01 sys=0.00, real=0.26 secs] - Notice that the entire heap usage has been reduced by more than just the 1,222 MB
removed from eden. That difference (16 MB) seems small, but remember that some of
the survivor space was promoted into the old generation at the same time; in addition,
each mixed GC cleans up only a portion of the targeted old generation regions. As we
continue, we’ll see that it is important to make sure that the mixed GCs clean up enough
memory to prevent future concurrent failures. - The mixed GC cycles will continue until (almost) all of the marked regions have been
collected, at which point G1 will resume regular young GC cycles. Eventually, G1 will
start another concurrent cycle to determine which regions should be freed next.
full GC
- As with CMS, there are times when you’ll observe a full GC in the log, which is an
indication that more tuning (including, possibly, more heap space) will benefit the application
performance. There are primarily four times when this is triggered: - Concurrent mode failure
- G1 starts a marking cycle, but the old generation fills up before the cycle is completed.
In that case, G1 aborts the marking cycle: - 51.408: [GC concurrent-mark-start]
65.473: [Full GC 4095M->1395M(4096M), 6.1963770 secs]
[Times: user=7.87 sys=0.00, real=6.20 secs]
71.669: [GC concurrent-mark-abort] - This failure means that heap size should be increased, or the G1 background processing
must begin sooner, or the cycle must be tuned to run more quickly (e.g., by
using additional background threads).
- G1 starts a marking cycle, but the old generation fills up before the cycle is completed.
- Promotion failure
- G1 has completed a marking cycle and has started performing mixed GCs to clean
up the old regions, but the old generation runs out of space before enough memory
can be reclaimed from the old generation. In the log, a full GC immediately follows
a mixed GC: - 2226.224: [GC pause (mixed)
2226.440: [SoftReference, 0 refs, 0.0000060 secs]
2226.441: [WeakReference, 0 refs, 0.0000020 secs]
2226.441: [FinalReference, 0 refs, 0.0000010 secs]
2226.441: [PhantomReference, 0 refs, 0.0000010 secs]
2226.441: [JNI Weak Reference, 0.0000030 secs]
(to-space exhausted), 0.2390040 secs]
….
[Eden: 0.0B(400.0M)->0.0B(400.0M)
Survivors: 0.0B->0.0B Heap: 2006.4M(2048.0M)->2006.4M(2048.0M)]
[Times: user=1.70 sys=0.04, real=0.26 secs]
2226.510: [Full GC (Allocation Failure)
2227.519: [SoftReference, 4329 refs, 0.0005520 secs]
2227.520: [WeakReference, 12646 refs, 0.0010510 secs]
2227.521: [FinalReference, 7538 refs, 0.0005660 secs]
2227.521: [PhantomReference, 168 refs, 0.0000120 secs]
2227.521: [JNI Weak Reference, 0.0000020 secs]
2006M->907M(2048M), 4.1615450 secs]
[Times: user=6.76 sys=0.01, real=4.16 secs] - This failure means the mixed collections need to happen more quickly; each young
collection needs to process more regions in the old generation.
- G1 has completed a marking cycle and has started performing mixed GCs to clean
- Evacuation failure
- When performing a young collection, there isn’t enough room in the survivor
spaces and the old generation to hold all the surviving objects. This appears in the
GC logs as a specific kind of young GC: - 60.238: [GC pause (young) (to-space overflow), 0.41546900 secs]
- This is an indication that the heap is largely full or fragmented. G1 will attempt to
compensate for this, but you can expect this to end badly: G1 will resort to performing
a full GC. The easy way to overcome this is to increase the heap size,
- When performing a young collection, there isn’t enough room in the survivor
- Humongous allocation failure
- Applications that allocate very large objects can trigger another kind of full GC in
G1; see “G1 allocation of humongous objects” on page 169. There are no tools to
diagnose that situation specifically from the standard GC log, though if a full GC
occurs for no apparent reason, it is likely due to an issue with humongous allocations.
- Applications that allocate very large objects can trigger another kind of full GC in
Quick Summary
- G1 has a number of cycles (and phases within the concurrent
cycle). A well-tuned JVM running G1 should only experience
young, mixed, and concurrent GC cycles. - Small pauses occur for some of the G1 concurrent phases.
G1 should be tuned if necessary to avoid full GC cycles.
CMS Collector and G1 Collector的更多相关文章
- The The Garbage-First (G1) collector since Oracle JDK 7 update 4 and later releases
Refer to http://www.oracle.com/technetwork/tutorials/tutorials-1876574.html for detail. 一些内容复制到这儿 Th ...
- G1 collector 介绍
背景:由于CMS算法产生空间碎片和其它一系列的问题缺陷,HotSpot提供了另外一种垃圾回收策略,G1(也就是Garbage First)算法,该算法在JDK7u4版本被正式推出,官网对此描述如下: ...
- G1垃圾收集器系统化说明【官方解读】
还是继续G1官网解读,上一次已经将这三节的东东读完了,如下: 所以接一来则继续往下读: Reviewing Generational GC and CMS[回顾一下CMS收集器] The Concur ...
- Java (JVM) Memory Model – Memory Management in Java
原文地址:http://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java Understanding JV ...
- Java Garbage Collection Basics--转载
原文地址:http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html Overview Purpose ...
- 垂直打击之JVM剖析
让Java应用程序运行是一回事,但让他们跑得快就是另外一回事了.在面对对象的环境中,性能问题就像来势凶猛的野兽.但JVM的复杂性将性能调整的复杂程度增加了一个级别.这里Refcard涵盖了JVM in ...
- Java基础学习总结(80)——Java性能优化详解
让Java应用程序运行是一回事,但让他们跑得快就是另外一回事了.在面对对象的环境中,性能问题就像来势凶猛的野兽.但JVM的复杂性将性能调整的复杂程度增加了一个级别.这里Refcard涵盖了JVM in ...
- 深入理解JVM(学习过程)
这,仅是我学习过程中记录的笔记.确定了一个待研究的主题,对这个主题进行全方面的剖析.笔记是用来方便我回顾与学习的,欢迎大家与我进行交流沟通,共同成长.不止是技术. 2020年02月06日22:43:0 ...
- Garbage Collectors – Serial vs. Parallel vs. CMS vs. G1 (and what’s new in Java 8)
转自:http://blog.takipi.com/garbage-collectors-serial-vs-parallel-vs-cms-vs-the-g1-and-whats-new-in-ja ...
随机推荐
- 常用的String原型
对于常用的字符串原型的举例 在字符串末尾追加字符串 String.prototype.append = function (str) { return this.concat(str);} 删除指定索 ...
- Sql server 2014 数据库还原奇异现象
用A库来还原B库 对正在使用的B库执行还原,还原时修改数据库名称,还原出错,提示数据库正在使用.删除B库,仍然提示正在使用,感觉像僵尸 重启SQL SERVER,因B库已删除,在A库上点击 ...
- android集成twitter登录
Twitter曾经举行了自己四年以来的第一场开发者大会.而这场名为“Flight”的大会,也是以后它的年度惯例. 这次大会的主题也完全围绕开发者进行.大会的焦点是一个名叫Fabric的新SDK,里面包 ...
- 简易仿ios菊花加载loading图
原文链接:https://mp.weixin.qq.com/s/wBbQgOfr59wntNK9ZJ5iRw 项目中经常会用到加载数据的loading显示图,除了设计根据app自身设计的动画loadi ...
- 从0开始的Python学习005运算符与表达式
地三鲜 土豆+茄子+青椒=地三鲜 这就是一个表达式,表达式是由运算符和操作数组成的. 土豆.茄子和青椒是操作数,炒是运算符,而地三鲜就是最后结果也就是这个表达式的值. 表达式 一个表达式可以分解为运 ...
- Burpsuite 之intruder
首先工具:Burpsuite1.7,DVWA,火狐浏览器代理插件,火狐浏览器,密码字典(以下用Bp代指burpsuite) 启动Bp,启动DVWA,并打开本地代理功能 开启bp的拦截功能,并在dv ...
- ATL右键文件菜单
自己写的小程序中用到的,网上资料相对还是毕竟全的,这里再整理下.毕竟我也不是很了解ATL,里面估计还是有不少问题的,就当作参考吧. 1.创建ATL工程,这个没什么好讲的. 我对COM组件没什么研究,这 ...
- MySql 学习之路-基础
Mysql 自学之路 本文包含基础部分与高级部分 一.基础 数据库操作 Show databases:显示所有的数据库 Show tables: 显示所有的数据库表 Use databasename: ...
- 安装和使用 memcached
memcached 和 Grails,第 1 部分:安装和使用 memcached 学习 memcached 命令并评估缓存性能 本文是系列文章的第 1 部分,主要介绍 memcached 和 Gra ...
- 网络流之P3254 圆桌问题
题目描述 假设有来自m 个不同单位的代表参加一次国际会议.每个单位的代表数分别为ri (i =1,2,……,m). 会议餐厅共有n 张餐桌,每张餐桌可容纳ci (i =1,2,……,n)个代表就餐. ...