G1收集器、理解GC日志和垃圾收集器参数总结
G1收集器
G1收集器是面向服务端应用的垃圾收集器,G1收集器具有以下几个特点:
- 并行与并发:G1收集器可以充分利用CPU,多核环境下的硬件优势,使用多个CPU来缩短停顿的时间,部分其他收集器需要停顿的GC动作,G1收集器可以让通过并发的形式让java程序继续执行
- 分代收集:分代概念仍在G1收集器中存在。虽然G1收集器可以不需要其他收集器就可以管理整个堆,但能够通过不同的方式去处理新创建,已经存活一段时间和熬过多次GC的对象,一次来获取更好的收集效果。
- 空间整合:G1收集器从整体来看更像是用"标价-整理"算法实现的收集器,从内部区域来看是基于复制算法实现的,这两种算法都意味着G1收集器不会产生过多的空间碎片,有利于程序长时间运行,在分配大对象时不会因为无法找到连续的内存空间而提前触发一次Full GC。
- 可预测的停顿:G1除了追求低停顿外,还可以建立可预测的停顿时间模型,能让使用者明确指定在一个指定长度m毫秒的时间片段内,消耗在垃圾收集的时间不得超过N毫秒。
使用G1收集器时,把整个堆内存分为多个大小相等的独立区域,虽然在G1收集器的仍然有新生代和老年代的概念,但新生代和老年代已经不在是物理上的隔离,他们都是独立区域的集合。
G1收集器之所以能建立可预测的停顿时间模型,是因为G1收集器有计划的避免进行全部内存区域的垃圾回收。G1通过跟踪每个独立区域里面需要回收的垃圾对象产生的价值,在后台维护一个列表,每次根据允许的收集时间,优先回收价值最高的独立区域(这也就是Carbage-First名称的来由)。这种使用独立区域划分内存空间的以及有优先级的区域回收方式,保证了G1收集器可以再有限的时间内获取较高的效率。
G1收集器的运行步骤
G1收集器的运行步骤大致可以分为下面几个步骤:
初始标价,并发标记,最终标记,筛选回收
下图是G1收集器的运行步骤中的并发和需要停顿的阶段:
理解GC日志
首先列出两段典型的GC日志:
图中每段GC日志中的33.125和100.667代表了GC的时间,即是从java虚拟机启动过来经过的秒数。
日志中开头的[GC和[Full Gc说明了这次垃圾收集的停顿类型,这里不是用来区分新生代和老年代的,如果有[Full Gc则说明这次GC发生了Stop-The-World。
下面这段日志信息是新生代收集器ParNew出现[Full Gc(这一般是因为分配担保失败之类的问题,所以才导致STW):
如果调用System.gc()方法触发的收集,将展示[Full Gc(System)
接下来的[DefNew,[Tenured,[Perm表示GC发生的区域,这里显示的区域名与使用的GC收集器是密切相关的。
后面方括号内部的"3324k->152k(3712k)",表示GC前该内存区域已使用的容量->GC后该内存区域使用的容量(该区域总容量),而在方括号之外的"3324k->152k(11904k)"表示GC前java堆已经使用的容量->GC后java堆使用的容量(Java堆的总容量)
日志中的0.0025925 secs表示该内存区域GC所占用的时间,单位是秒。