JVM G1详解

java程序性能

当我们调优java程序时,通常的目标有两个: 
响应能力 或者 吞吐量

响应能力

响应能力指一个程序或者系统对请求的是否能够及时响应。 
比如: 
一个桌面UI能多快的响应一个事件; 
一个网站能够多快返回一个页面请求; 
数据库能够多快返回查询的数据;

对于这类对响应能力敏感的场景,长时间的停顿是无法接受的。

吞吐量

吞吐量关注的是,在一个指定的时间内,最大化一个应用的工作量。 
如下方式来衡量一个系统吞吐量的好坏:

在一小时内同一个事务(或者任务、请求)完成的次数(tps)。 
数据库一小时可以完成多少次查询;

对于关注吞吐量的系统,卡顿是可以接受的,因为这个系统关注长时间的大量任务的执行能力,单次快速的响应并不值得考虑。

应用程序运行实际/实际时间(开始时间戳-结束时间戳)

understanding TPS

G1 Garbage Collector

G1垃圾收集器

g1收集器是一个面向服务端的垃圾收收集器,适用于多核处理器、大内存容量的服务端系统。 
它满足短时间gc 停顿的同时达到一个高的吞吐量。JDK7以上版本适用。

g1收集器的设计目标:

与应用线程同时工作,几乎不需要stop-the-world(与CMS类似); 
整理剩余空间,不产生内存碎片;(CMS只能在full-GC时,用stop-the-world整理碎片内存) 
GC停顿更加可控; 
不牺牲系统的吞吐量; 
gc不要求额外的内存空间(CMS需要预留空间存储浮动垃圾);

G1的设计规划,是要替换掉CMS。

G1在某些方便弥补了CMS的不足,比如,CMS使用的是mark-sweep算法,自然会产生内存碎片;然而G1基于copying算法,高效的整理剩余内存,而不需要使用free-list去管理内存碎片。 
另外,G1提供了更多手段,以达到对gc停顿时间可控。

之前的GC收集器对Heap的划分:

这里写图片描述

G1对Heap的划分:

这里写图片描述

heap被划分为一个个相等的不连续的内存区域(regions),每个region都有一个分代的角色:eden、survivor、old(old还有一种细分 humongous,用来存放大小超过 region 50%以上的巨型对象)。

但是对每个角色的数量并没有强制的限定,也就是说对每种分代内存的大小,可以动态变化(默认年轻代占整个heap的5%)。

G1最大的特点就是高效的执行回收,优先去执行那些大量对象可回收的区域(region)。

另外,G1使用了gc停顿可预测的模型,来满足用户设定的gc停顿时间,根据用户设定的目标时间,g1会自动的选择哪些region要清楚,一次清除多少个region。

G1从多个region中复制存活的对象,然后集中放入一个region中,同时整理、清除内存(copying收集算法)。

注意对比之前的垃圾收集器(主要是CMS): 
对比使用mark-sweep的CMS,g1使用的copying算法不会造成内存碎片; 
对比ParallelScavenge(基于copying )、ParallelOld收集器(基于mark-compact-sweep),Parallel 
会对整个区域做整理导致gc Pause会比较长,而g1只是特定的整理几个region。

值得注意:g1不是一个实时的收集器,与parallelScavenge一样,对gc 停顿时间的设置并不绝对生效,只是g1有较高的几率保证不超过设定gc停顿时间。与之前的gc收集器对比,g1会根据用户设定的gc停顿时间,智能评估一下哪几个region需要被回收可以满足用户设定。

G1内存的分配

1.TLAB(TLAB占用年轻代内存). 默认使用TLAB加速内存分配,之前文章已经讲过,不赘述。 
2.Eden.如果TLAB不够用,则在Eden中分配内存生成对象。 
3.Humongous.如果对象需要的内存超过一个region的50%以上,会忽略前两个步骤直接在老年代的humongous中分配(连续的Region)。

何时使用G1(-XX:+UseG1GC)

1.大内存中为了达到低gc延迟. 
比如:heap size >=6G,gc pause <=0.5s 
2.FullGC时间太长,或者太频繁。

调优参数: 
-XX:MaxGCPauseMillis=200 
用户设定的最大gc 停顿时间,默认是200ms. 
-XX:InitiatingHeapOccupancyPercent=45 
默认是45,也就是heap中45%的容量被使用,则会触发concurrent gc。

G1垃圾回收步骤详解

G1提供了两种GC模式,Young GC和Mixed GC,两种都是Stop The World(STW)的

G1 Young GC(STW)

1.当eden数据满了,则触发g1 YGC 
2.并行的执行: 
YGC 将 eden region 中存活的对象拷贝到survivor,或者直接晋升到Old Region中;将Survivor Regin中存活的对象拷贝到新的Survivor或者晋升old region。 
3.计算下一次YGC eden、Survivor的尺寸

G1 Mix GC

在G1 GC中,它主要是为Mixed GC提供标记服务的,并不是一次GC过程的一个必须环节。global concurrent marking的执行过程分为五个步骤:

初始标记(initial mark,STW) 
在此阶段,G1 GC 对根进行标记。该阶段与常规的 (STW) 年轻代垃圾回收密切相关。

根区域扫描(root region scan) 
G1 GC 在初始标记的存活区扫描对老年代的引用,并标记被引用的对象。该阶段与应用程序(非 STW)同时运行,并且只有完成该阶段后,才能开始下一次 STW 年轻代垃圾回收。

并发标记(Concurrent Marking) 
G1 GC 在整个堆中查找可访问的(存活的)对象。该阶段与应用程序同时运行,可以被 STW 年轻代垃圾回收中断

最终标记(Remark,STW) 
该阶段是 STW 回收,帮助完成标记周期。G1 GC 清空 SATB 缓冲区,跟踪未被访问的存活对象,并执行引用处理。

清除垃圾(Cleanup,STW) 

在这个最后阶段,G1 GC 执行统计和 RSet 净化的 STW 操作。在统计期间,G1 GC 会识别完全空闲的区域和可供进行混合垃圾回收的区域。清理阶段在将空白区域重置并返回到空闲列表时为部分并发。


一、G1收集器简介

  1. G1收集器(JDK1.7u4正式出现) 
    这里写图片描述

普遍存在:全内存扫描问题。 
传统的收集器不能满足高内存高cpu的要求,这才是G1产生的原因。

2.G1区域划分 
这里写图片描述

在G1之中不再区分所谓的年轻代、老年代内存空间,所有的内存空间就是一块。但是要划分出不同的子区域。

二、G1收集策略

虽然在G1收集器里面将整个内存区域都混合在了一起,但是其本身依然也是在小范围内要进行年轻代与老年代的区分,也就是说依然会采用不同的GC方式来处理不同的区域。

G1——年轻代有对象 
这里写图片描述

G1——年轻代对象被回收 
这里写图片描述

所有的垃圾内存的保存区域有可能会被清空后重新分配。

但是老年代的处理流程不一样了,因为任何时候如果要想标注老年代的不用内存空间,都需要进行一些暂停,而G1之中的最大好处它不用进行全内存扫描,只需要按照区域来进行扫描即可。

G1老年代回收 
这里写图片描述

G1——老年代,标记阶段 
这里写图片描述

G1——老年代,根区域扫描 
这里写图片描述

G1——老年代,重新标记阶段 
这里写图片描述

G1——老年代,清理、拷贝阶段 
这里写图片描述

G1——清理完毕 
这里写图片描述

三、G1相关处理参数

清楚了G1的基本运行原理之后,那么下面就需要进行一些G1的配置。(需慎重使用,可能会有一些问题出现)

G1收集器参数 
这里写图片描述

范例:使用G1回收器

java -Xmx10m -Xms10m -XX:+UseG1GC -XX:+PrintGCDetails TestDemo
  • 1

G1处理和传统的垃圾收集策略是不同的,关键的因素是它将所有的内存进行了子区域的划分。


g1 对老年代回收-总结:

1.并发标记阶段(Concurrent Marking Phase): 
在不产生stop-the-world,与程序进程并发的情况下,活跃度(可达性分析)被分析出来。 
活跃度越低,代表回收的效率越高,越值得优先回收。 
2.复制、清理阶段(Copying/Cleanup Phase) 
年轻代、老年代在这个阶段同时被回收掉。老年代被回收的region,是根据这个region的存活度来选择的。

正因为当初对未来做了太多的憧憬,所以对现在的自己尤其失望。生命中曾经有过的所有灿烂,终究都需要用寂寞来偿还。
原文地址:https://www.cnblogs.com/candlia/p/11920155.html