GC调整策略

更新时间:2023-06-17 00:11:57 阅读: 评论:0

GC调整:
调整目标
随着 Java 的演化,当初 C vs. Java 大战渐趋缓和:
Java: 老兄! malloc / free 就是一名艺术?
C: 好钢用到刀刃上,总感觉 GC 忙个不停一直占着资源在清理“垃圾”


梦幻 GC 应该是这样子:
1. 低开销 (low overhead)
under the dome2. 低停顿时间 (low pau time)
3. 有效的空间利用率 (space efficient)

但通常,我不得不从以上中来个”aspen口语交际练习三选二”,因为不同的程序对GC有不同的需求:
1. 吞吐量 (Throughput) - 花费在非GC的工作时间,也就是说GC时间是反吞吐量的 (这就是上述 C 老兄嘲笑的原因)
-
-XX:GCTimeRatio =ratio (粗调,只是个 hint,能否达到取决于系统状态)
- GC 时间对应用时间的比率: 1 / (1 + n)
- 例如: -XX:GCTimeRatio=19 设定 5% (1/(1+19)) GC 时间; -XX:GCTimeRatio=99 设定 1% (1/(1+99)) GC 时间
2. 开销 (Overhead) - 即反吞吐量,即 GC 所占的时间
3. 停顿时间 (Pau) - 由于GC 正在运行,程序看起来没响应的时长
- -XX:MaxGCPauMillis=n (粗调,只是个 hint,能否达到取决于系统状态)
- GC 将尽最大努力调整相应参数来满足这一要求,也许会以降低吞吐量为代价翌日是什么意思
4. GC频率 (GC Frequency) - 相对应用执行时间,GC执行的频率
5. 空间利用率 (Footprint, 这个单词找不到准确的中文) - 完成GC功能需要的空间。 因为硬件的 cache line, memory, page 总是稀缺的,GC占去越多意味着真正用来干活的就越少
jiujie6. 敏捷性 (Promptness) – 当对象变成垃圾了,多长时间它才被清理掉。也就是多长时间一个垃圾对象所占的内存被收回。包括分配式垃圾收集(Distributed Garbage Collection -DGC),如在RMI 场景

调整策略
1. 对所有GC适用
1. 来个超大号的总没错!
- 但是,最大值 <= 1/2 系统内存(除非你跑着玩,因为另一半留给操作系统其它看家进程和 mmap)
- 且JVM能访问到的最大值因操作系统而异 (java -Xmx)
2. 平衡
- 堆空间,通常是越大越好,无论对 young 还是对 Old Generation 来说
- 大的空间意味着GC不那么频繁,因此留有时间给对象成为“垃圾”
- 对于 Young Generation 因为频繁的GC,本该成为垃圾的对象,会被过早地搬到 Survivor Space,进到那里的对象,如果存活,会占去来回在 S0 <-> S1 中拷贝的消耗。
- 对于 Old Generation 我们希望,在一次GC过程中尽量多清除些垃圾,但频繁的GC活动,有时会显得过早(因为,也许过不了多久,又有一大批对象消亡)
- 但小的空间或许意味着GC每一趟可以更快地结束 (但并不总是这样,如CMS)
3. Young Generation 大小
因为 minor GC 频繁地运行,minor GC 算法的目标是快速。因此参数的选择不要违背这一宗旨

- Young 整体空间大小调整
- -XX: newSize=<n> : 初始 young generation 大小负责人 翻译
- -XX:MaxNewSize=<n> : 最大 young generation 大小
- -Xmn n 更可取,因为它综合了 -XX:NewSize=<n> 和 -XX:MaxNewSize=<n>
- 如果使用上述任一种方案指定 young generation 大小,那么 -XX:NewRatio=<ratio > 不再需要: young generation 与 old generation 的比率,如 ratio =3 表示 young/old = 1/3
- CPU 核心增加了,适量增加 young generation 大小以充分利用并行,如果 heap size 固定了,那么增加 young generation 则意味着 old generation 减少,确保 old generation 足够大以容纳任何时候所有 live 对象 + 20% 空闲
- Eden空间调整
- 该大小意味着 minor GC 的频率,越小越容易填满,因此频率越高(不利于对象成为垃圾)
- 该大小还意味着有多少比例的对象可以被夭折在伊甸园中(age=0),而不必花力气将他们
搬到Survivor Space (age >0),进而送往 Old Generation,最后在 Major collection 中耗费力气
- 增加 Eden 大小并不总是减小 minor collection 的时间,因为 minor collection 时间花费在 拷贝Eden 中的 age=0的对象到 survivor space,以及处理 survivor space 中的 age>0 的对象
- -XX:SurvivorRatio=<ratio> (见下面)
- Survivor 调整
- -XX:SurvivorRatio=<ratio> 单个 Survivor Space 与 Eden 的比例,例如,ratio=6 表示 每个 Survivor / Eden = 1/6 (即,每个 Survivor 是整个 Young Generation 的 1/8,因为有两个 Survivor Space)
- -XX:TargetSurvivorRatio=<percent> 在每个(因为有两个) Survivor Space 到达这一比率时,将被提升到 old generation 中
- -XX:InitialTenuringThreshold=<threshold> 因为是自适应(adaptive)GC, 初始值,在被提升到 old generation 之前,对象可在 young generation 存活的次数
- -XX:MaxTenuringThreshold=<threshold> 因为是自适应(adaptive)GC, 最大值,在被提升
到 old generation 之前,对象可在 young generation 存活的次数
- -XX:+AlwaysTenure 从不将对象保留在 Survivor Space, 即每次 minor GC 直接将对象送往 Old Generation。对于应用包括很多 mid/long time live 对象适用,因为 可以避免在 Survivor Space 中来回拷贝的开销
- 权衡
- 对于 mid/long live time 对象的比例小的应用
- 尽可能多地将对象呆在 survivor space, 因为这样可以将他们在 young generation 就被回收
在线翻译汉译英- 更少提升到 old generation
- 低频繁 major GC
- 对于mid/long live time 对象的比例大的应用
- 尽量避免来回在 survivor space 中拷贝,因为他们最终是进到 old generation
- 但是,很难预言对象的生命周期长还是短,一般来说,在 survivor space 中拷贝比无谓地提升到 old generation 还是要好点
- -XX:+PrintTenuringDistribution 用于监视 survivor size 的行为分配,并给出合适的 surviv
or 空间大小建议
4. Old Generation 大小
- Major collection 最主要目标是更好的空间利用率,而不是快速
- 尽可能减少 major collection 的频率
- 最好能容纳应用“稳态”时的活对象总大小 (说起来容易,做起来难,能容易地预测 WEB 服务器的高峰与空闲状态负载的回归线么?能很容易地预测分布式存储系统的 read write 比么?)。并适用加上20% 空闲
- -Xms == -Xmx
- 当 -Xms != -Xmx,堆的扩张或收缩需要 Full GC (什么是 Full GC?在大多数情况下,其等同于 major GC, 但在 i-cms 增量并发标记清扫 GC 模式下,有些不一样。)
- -Xmx<n> 最大堆大小 (young generation + old generation)
- -Xms<n> 初始堆大小 (young generation + old generation)
- -Xmn<n> young generation 大小
- 因此,-XX:MinHeapFreeRatio=<minimum> -XX:MaxHeapFreeRatio=<maximum> 不再需要
-
-Xms != -Xmx 也许适用于应用在整个生命周期中稳态的活对象总大小为 -Xms 赋的大小,但也许会在极小的情况下峰值负载(如 WEB 服务器)或数据集(存储系统)将达到 -Xmx赋的值。但是,是以增长堆空间大小的开销为代价的(Full GC)。因为,此时,GC 别无选择,在 OOME 导致 crash 之前,尽最大努力做一次 Full GC是值得的。
5. Permanent Generation大小调整
- -XX:PermSize == -XX:MaxPermSize, 同样,因为 permanent 堆扩张或收缩需要 Full GC
- -XX:PermSize=<n> permanent generation 初始大小
- -XX:MaxPermSize=<n> permanent generation 最大值
- 通常,我们不幸地很难拿捏这个值
6. 禁止自适用策略
- 采用固定大小策略,还意味着 -XX:YoungGenerationSizeIncrement=<m> -XX:TenuredGenerationSizeIncrement=<n> -XX:AdaptiveSizeDecrementScaleFactor=<r> 都不需要
7. 尽可能多地在对象还在 Young Generation 时将其回收
- 如果对象不是 long-live 对象,最好在 minor collection 时就将其回收。否则,
-
转入 Old Generation,major collection 发生的频率低,会增加 Footprint
- 越多的 old generation垃圾,是终导致 major collection 频率升高和GC时间更长
8. Footprint 不应该超过系统可用的物理内存
- 如果 Swap 开启(对于服务器应用,并不是好主意),swap in/out 或许可能缓解一会儿,但是程序将遭受 内存与I/O 访问的时间的差异 + swap 时间。
- 如果 Swap 没开启,哈哈,OOME
- 对于个别 GC, 即使 swap 开启,如果大部分时间花在 swap in/out 蚂蚁搬家的话,也一样 OOME
- 通常,目前的操作系统都有 mmap 用于 I/O,所以,不要贪心地将所有系统物理内存让 JVM 独吞。这样的话,你将失去来自操作系统的,免费而超优化的缓存功能!


2. 对Parallel GC / Parallel Old GC
1. 默认情况下,该GC 认为它承载的系统只有它一个JVM
2. XX:ParallelGCThreads=<n> 指定并行的线程数
-
考虑系统是否有多个JVM
- 系统的处理器核心个数
- 处理器是否支持一个核心多个硬件线程 (比如:优秀的UltraSPARC T1/T2)
3. –XX:MaxGCPauMillis=n 指定最大 pau time
4. –XX:GCTimeRatio=n 指定GC 花费时间与总体时间的比率:1/(1+n)
5. 因为 Parallel GC 为当今主流硬件开发并采用 ergonomics,因此默认情况下它自动调整过了,除非这种默认遇到严重问题
6. 首先按照前述调整 young generation
7. 降低 major GC 的频率
8. 用于 low-pau 环境
- 通过最大化 heap 空间
- 通过避免或最小化 Survivor promotion 来避免 Full GC

quantitative
3. 给 CMS高中英语必修一单词
1. 首先按照前述调整 young generation
- 别错误地认为,因为 CMS 并发能力发生在 old generation,因此忽略 young generation 的调整。
2. 更加小心地避免 过早的Survivor Space promotion
- CMS 因为采用 free lists 的原因,提升开销很大
- 越频繁的 Survivor Space promotion 越有可能造成堆碎片(fragmentation )
3. 只调整 minor GC 同样可以利用 CMS
- CMS 只作为最后一道防线,在应用负载超过以往的最大值时
- 将 Full GC 安排在非关键时间段以减少堆碎片(fragmentation )
4. 无法避免堆碎片(fragmentation )
- 最终导致找不到足够大的空间来完成分配请求,即使 free 空间总计大小大于分配请求大小
- 分配器为了效率,采用近似策略,这近似值最终浪费不少空闲空间
- 不同大小的“大对象”是元凶
5. -XX:ParallelCMSThreads=<n> 并行的 CMS 线程数
6. –XX:+CMSIncrementalMode 启用增量模式
7. –XX:+CMSIncrementalPacing 控制增量模式下,每次的工作量
8. 卸载 permanent generation 中的类
- 默认情况下,CMS 不卸载 permanent generation 中的类
- -XX:+CMSClassUnloadingEnabled -XX: +PermGenSweepingEnabled 激活卸载
9. CMS 启动时机
- 前面的算法描述部分介绍了CMS GC 需要提前启动以避免回退到 Serial Mark-Sweep-Compact 模式
- 启动太早,将导致频繁的 GC 周期以及高并发的开销
- 启动太晚,最终回退到Serial Mark-Sweep-Compact 模式 Full GC。没有利用到 CMS 的优势
- -XX:+UCMSInitiatingOccupancyOnly - 默认情况下,CMS 会自动统计来找到最佳启动时机(即 ergonomic 机制),但是为了采用下面的控制参数,需要使该ergonomic 机制失效
- -XX:CMSInitiatingOccupancyFraction=<percent> - 当 old generation 占用率达到这一百分比时,启动 CMS GC
-
-XX:CMSInitiatingOccupancyFraction=<percent> - 由这个配置算出的结果(占有大小)应该比应用“稳态”下的 所有live 对象大小大得多,否则,CMS 将不停地发生。因为一达到这个百分比就会触发
- -XX:CMSInitiatingPermOccupancyFraction=<percent> 当 permanent generation 占用率达到这一百分比时,启动 CMS GC (前提是 -XX:+CMSClassUnloadingEnabled 激活了)
- 对于 mid/long live time 对象的比例小的应用,可以晚些启动,因为:
- 很少 Survivor Space promotion发生
- old generation 增长缓慢
- 低频率地 major GC (即 CMS GC)
- 对于 mid/long live time 对象的比例大的应用,相对早些启动,因为:
- 很多 Survivor Space promotion发生owning
- old generation 增长很快
- 高频率地 major GC (即 CMS GC)
10. 使 () 明确地使用 CMS
- () 总是进行一次 Full GC, 即使没有必要,所以 -XX:+DisableExplicitGC 可以用
来忽略所有的 () 调用
- -XX:+ExplicitGCInvokesConcurrent / -XX:+ExplicitGCInvokesConcurrentAndUnloadClass 指定 ()采用 CMS 算法
- 对于应用信赖于 Sofe, Weak, Phantom references / finalizers 时有用
(Serial GC 就不单独调整了,因为除非是 Embedded JAVA, 否则,它会慢慢地消失!)

本文发布于:2023-06-17 00:11:57,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/147558.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:时间   对象   空间   应用   系统   垃圾
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图