您的位置:首页 > 编程语言 > Java开发

java g1垃圾回收

2017-01-17 17:24 281 查看
Hotspot 架构图



紫色为调优的主要地方

G1 垃圾收集器(Garbage Collector)

G1 垃圾收集器

G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征. 在Oracle JDK 7 update 4 及以上版本中得到完全支持, 专为以下应用程序设计:

可以像CMS收集器一样,GC操作与应用的线程一起并发执行

紧凑的空闲内存区间且没有很长的GC停顿时间.

需要可预测的GC暂停耗时.

不想牺牲太多吞吐量性能.

启动后不需要请求更大的Java堆.

G1的长期目标是取代CMS(Concurrent Mark-Sweep Collector, 并发标记-清除). 因为特性的不同使G1成为比CMS更好的解决方案. 一个区别是,G1是一款压缩型的收集器.G1通过有效的压缩完全避免了对细微空闲内存空间的分配,不用依赖于regions,这不仅大大简化了收集器,而且还消除了潜在的内存碎片问题。除压缩以外,G1的垃圾收集停顿也比CMS容易估计,也允许用户自定义所希望的停顿参数(pause targets)

g1 垃圾收集器将内存模型改变了



注意 G1分为两个阶段: 并发阶段(concurrent, 与应用线程一起运行, 如: 细化 refinement、标记 marking、清理 cleanup) 和 并行阶段(parallel, 多线程执行, 如: 停止所有JVM线程, stop the world). 而 FullGC(完整垃圾收集)仍然是单线程的, 但如果进行适当的调优,则应用程序应该能够避免 full GC。

推荐使用 G1 的场景(Recommended Use Cases)

G1的首要目标是为需要大量内存的系统提供一个保证GC低延迟的解决方案. 也就是说堆内存在6GB及以上,稳定和可预测的暂停时间小于0.5秒.

如果应用程序具有如下的一个或多个特征,那么将垃圾收集器从CMS或ParallelOldGC切换到G1将会大大提升性能.

Full GC 次数太频繁或者消耗时间太长.

对象分配的频率或代数提升(promotion)显著变化.

受够了太长的垃圾回收或内存整理时间(超过0.5~1秒)

注意: 如果正在使用CMS或ParallelOldGC,而应用程序的垃圾收集停顿时间并不长,那么继续使用现在的垃圾收集器是个好主意. 使用最新的JDK时并不要求切换到G1收集器。

G1 的 GC 参数完全列表

选项/默认值 说明

-XX:+UseG1GC 使用 G1 (Garbage First) 垃圾收集器

-XX:MaxGCPauseMillis=n 设置最大GC停顿时间(GC pause time)指标(target). 这是一个软性指标(soft goal), JVM 会尽量去达成这个目标.

-XX:InitiatingHeapOccupancyPercent=n 启动并发GC周期时的堆内存占用百分比. G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比. 值为 0 则表示”一直执行GC循环”. 默认值为 45.

-XX:NewRatio=n 新生代与老生代(new/old generation)的大小比例(Ratio). 默认值为 2.

-XX:SurvivorRatio=n eden/survivor 空间大小的比例(Ratio). 默认值为 8.

-XX:MaxTenuringThreshold=n 提升年老代的最大临界值(tenuring threshold). 默认值为 15.

-XX:ParallelGCThreads=n 设置垃圾收集器在并行阶段使用的线程数,默认值随JVM运行的平台不同而不同.

-XX:ConcGCThreads=n 并发垃圾收集器使用的线程数量. 默认值随JVM运行的平台不同而不同.

-XX:G1ReservePercent=n 设置堆内存保留为假天花板的总量,以降低提升失败的可能性. 默认值是 10.

-XX:G1HeapRegionSize=n 使用G1时Java堆会被分为大小统一的的区(region)。此参数可以指定每个heap区的大小. 默认值将根据 heap size 算出最优解. 最小值为 1Mb, 最大值为 32Mb.

最佳实践

在使用 G1 作为垃圾收集器时,你应该遵循下面这些最佳实践的指导.

不要设置年轻代的大小(Young Generation Size)

假若通过 -Xmn 显式地指定了年轻代的大小, 则会干扰到 G1收集器的默认行为.

G1在垃圾收集时将不再关心暂停时间指标. 所以从本质上说,设置年轻代的大小将禁用暂停时间目标.

G1在必要时也不能够增加或者缩小年轻代的空间. 因为大小是固定的,所以对更改大小无能为力.

响应时间指标(Response Time Metrics)

设置 XX:MaxGCPauseMillis= 时不应该使用平均响应时间(ART, average response time) 作为指标,而应该考虑使用目标时间的90%或者更大作为响应时间指标. 也就是说90%的用户(客户端/?)请求响应时间不会超过预设的目标值. 记住,暂停时间只是一个目标,并不能保证总是得到满足.

什么是转移失败(Evacuation Failure)?

对 survivors 或 promoted objects 进行GC时如果JVM的heap区不足就会发生提升失败(promotion failure). 堆内存不能继续扩充,因为已经达到最大值了. 当使用 -XX:+PrintGCDetails 时将会在GC日志中显示 to-space overflow (to-空间溢出)。

这是很昂贵的操作!

GC仍继续所以空间必须被释放.

拷贝失败的对象必须被放到正确的位置(tenured in place).

CSet指向区域中的任何 RSets 更新都必须重新生成(regenerated).

所有这些步骤都是代价高昂的.

如何避免转移失败(Evacuation Failure)

要避免避免转移失败, 考虑采纳下列选项.

增加堆内存大小

增加 -XX:G1ReservePercent=n, 其默认值是 10.

G1创建了一个假天花板(false ceiling),在需要更大 ‘to-space’ 的情况下会尝试从保留内存获取(leave the reserve memory free).

更早启动标记周期(marking cycle)

通过采用 -XX:ConcGCThreads=n 选项增加标记线程(marking threads)的数量.

设置日志细节(Log Detail)

可以设置3种不同的日志级别.

(1) -verbosegc (等价于 -XX:+PrintGC) 设置日志级别为 好 fine.

日志输出示例

[GC pause (G1 Humongous Allocation) (young) (initial-mark) 24M- >21M(64M), 0.2349730 secs]

[GC pause (G1 Evacuation Pause) (mixed) 66M->21M(236M), 0.1625268 secs]

(2) -XX:+PrintGCDetails 设置日志级别为 更好 finer. 使用此选项会显示以下信息:

每个阶段的 Average, Min, 以及 Max 时间.

根扫描(Root Scan), RSet 更新(同时处理缓冲区信息), RSet扫描(Scan), 对象拷贝(Object Copy), 终止(Termination, 包括尝试次数).

还显示 “other” 执行时间, 比如选择 CSet, 引用处理(reference processing), 引用排队(reference enqueuing) 以及释放(freeing) CSet等.

显示 Eden, Survivors 以及总的 Heap 占用信息(occupancies).

日志输出示例

[Ext Root Scanning (ms): Avg: 1.7 Min: 0.0 Max: 3.7 Diff: 3.7]

[Eden: 818M(818M)->0B(714M) Survivors: 0B->104M Heap: 836M(4096M)->409M(4096M)]

(3) -XX:+UnlockExperimentalVMOptions -XX:G1LogLevel=finest 设置日志级别为 最好 finest. 和 finer 级别类似, 包含每个 worker 线程信息.

[Ext Root Scanning (ms): 2.1 2.4 2.0 0.0

Avg: 1.6 Min: 0.0 Max: 2.4 Diff: 2.3]

[Update RS (ms): 0.4 0.2 0.4 0.0

Avg: 0.2 Min: 0.0 Max: 0.4 Diff: 0.4]

[Processed Buffers : 5 1 10 0

Sum: 16, Avg: 4, Min: 0, Max: 10, Diff: 10]

Determining Time

有两个参数决定了GC日志中打印的时间显示形式.

(1) -XX:+PrintGCTimeStamps - 显示从JVM启动时算起的运行时间.

日志输出示例

1.729: [GC pause (young) 46M->35M(1332M), 0.0310029 secs]

(2) -XX:+PrintGCDateStamps - 在每条记录前加上日期时间.

日志输出示例

2012-05-02T11:16:32.057+0200: [GC pause (young) 46M->35M(1332M), 0.0317225 secs]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java