JVM 调优参数总结

x33g5p2x  于2021-09-18 转载在 Java  
字(4.1k)|赞(0)|评价(0)|浏览(168)

杂谈

项目验收前夕,老大来一句:谁有兴趣调一调jvm参数?我我我我我!!!(即便啥都不会,只有理论从未实践,也不妨我抓住这难得的机会,反正有人兜底~)

很多人都说调 JVM 最终目的是为了让 Full gc 的次数减少,这样说对,也不对,因为过程中还是有许多可操作的地方,最后想想还是稍微做一点总结,以免自己忘记。(整理基于 大佬的建议 / 网络的资料 /《深入理解Java虚拟机》)

JVM参数

基本参数

  • -Xss:每个线程的栈大小
  • -Xms:初始堆大小,默认物理内存的1/64
  • -Xmx:最大堆大小,默认物理内存的1/4
  • -Xmn:新生代大小
  • -XX:NewSize:设置新生代初始大小
  • -XX:NewRatio:默认2表示新生代占年老代的1/2,占整个堆内存的1/3
  • -XX:SurvivorRatio:默认8表示一个survivor区占用1/8的Eden内存,即1/10的新生代内存
  • -XX:MaxMetaspaceSize: 设置元空间最大值, 默认是-1, 即不限制
  • -XX:MetaspaceSize: 指定元空间触发Fullgc的初始阈值,默认是21M

ps( MaxMetaspaceSize 和 MetaspaceSize 最好设置成一样,并且最好大于默认的21M ,由于元空间调整会导致 Full GC,将值设置为一样就能有效避免 Full GC )

其他参数

指针压缩

jdk1.6 update14开始,在64bit操作系统中,JVM支持指针压缩

在64位平台的HotSpot中使用32位指针,内存使用会多出1.5倍左右,使用较大指针在主内存和缓存之间移动数据,为了减少64位平台下内存的消耗,启用指针压缩功能

堆内存小于4G时,不需要启用指针压缩,jvm会直接去除高32位地址,即使用低虚拟地址空间,堆内存大于32G时,压缩指针会失效,会强制使用64位(即8字节)来对java对象寻址,这就会出现问题,所以堆内存不要大于32G为好

启用指针压缩:­ **-XX:+UseCompressedOops**(默认开启)
禁止指针压缩:­ **-XX:­UseCompressedOops**

逃逸分析

JDK7之后默认开启逃逸分析

对象逃逸分析:就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用。

JVM通过逃逸分析确定该对象不会被外部访问。如果不会逃逸可以将该对象在 栈上分配内存,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力。(优化对象内存分配位置)

开启逃逸分析:-XX:+DoEscapeAnalysis
关闭逃逸分析:-XX:-DoEscapeAnalysis

Eden

都知道 ,Eden 区空间不够,会发生 Minor GC,次数达到计数器阈值,会进入 老年代,最终引发 Full Gc(默认15,cms 默认6)

设置计数器阈值:-XX:MaxTenuringThreshold

理论上,只需要让eden区尽量的大,survivor区够用即可。

Eden与Survivor区默认8:1:1 可设置开启比例自动变化:

开启比例自动变化:-XX:+UseAdaptiveSizePolicy(默认开启)
关闭比例自动变化:-XX:-UseAdaptiveSizePolicy

Old

老年代回收,是导致发生Full Gc 的关键。

较大对象对直接进入老年代

这是为了避免为大对象分配内存时的复制操作而降低效率。

当超过某个阈值,会直接进入老年代而不是年轻代。

设置阈值:-XX:PretenureSizeThreshold

ps(这个参数只在 Serial 和ParNew两个收集器下有效。)

对象动态年龄判断

当前放对象的Survivor区域里(其中一块区域,放对象的那块s区),一批对象的总大小大于这块Survivor区域内存大小的50%(-XX:TargetSurvivorRatio可以指定),那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了,例如Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代。

这个规则其实是希望那些可能是长期存活的对象,尽早进入老年代。对象动态年龄判断机制一般是在minor gc之后触发的。

老年代空间分配担保机制

年轻代每次minor gc之前JVM都会计算下老年代剩余可用空间,如果这个可用空间小于年轻代里现有的所有对象大小之和(包括垃圾对象),就会看一个“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了,如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的平均大小。

如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾,如果回收完还是没有足够空间存放新的对象就会发生"OOM"

当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老年代可用空间,那么也会触发Full Gc,Full Gc完之后如果还是没有空间放minor gc之后的存活对象,则也会发生“OOM

ps(此机制有可能使得发生一次 minor gc 会发生 两次 Full Gc。)

垃圾收集器

ParNew收集器(-XX:+UseParNewGC) (用于配合CMS)

CMS收集器(-XX:+UseConcMarkSweepGC(old))

ps(这里不对收集器做讲解,因为讲的不好,哈哈)

CMS的相关核心参数:

  • -XX:+UseConcMarkSweepGC:启用cms
  • -XX:ConcGCThreads:并发的GC线程数
  • -XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理(减少碎片)
  • -XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一次
  • -XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(默认是92%)
  • -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整
  • -XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,目的在于减少老年代对年轻代的引用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段。
  • -XX:+CMSParallellnitialMarkEnabled:表示在初始标记的时候多线程执行,缩短STW。
  • -XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,缩短STW
G1(-XX:+UseG1GC)
  • -XX:+UseG1GC:使用G1收集器
  • -XX:ParallelGCThreads:指定GC工作的线程数量
  • -XX:G1HeapRegionSize:指定分区大小(1MB~32MB,且必须是2的N次幂),默认将整堆划分为2048个分区
  • -XX:MaxGCPauseMillis:目标暂停时间(默认200ms)
  • -XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%)
  • -XX:G1MaxNewSizePercent:新生代内存最大空间
  • -XX:TargetSurvivorRatio:Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄1+年龄2+年龄n的多个年龄对象)总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代
  • -XX:MaxTenuringThreshold:最大年龄阈值(默认15)
  • -XX:InitiatingHeapOccupancyPercent:老年代占用空间达到整堆内存阈值(默认45%),则执行新生代和老年代的混合收集(MixedGC),比如我们之前说的堆默认有2048个region,如果有接近1000个region都是老年代的region,则可能就要触发MixedGC了
  • -XX:G1MixedGCLiveThresholdPercent(默认85%) region中的存活对象低于这个值时才会回收该region,如果超过这个值,存活对象过多,回收的的意义不大。
  • -XX:G1MixedGCCountTarget:在一次回收过程中指定做几次筛选回收(默认8次),在最后一个筛选回收阶段可以回收一会,然后暂停回收,恢复系统运行,一会再开始回收,这样可以让系统不至于单次停顿时间过长。
  • -XX:G1HeapWastePercent(默认5%): gc过程中空出来的region是否充足阈值,在混合回收的时候,对Region回收都是基于复制算法进行的,都是把要回收的Region里的存活对象放入其他Region,然后这个Region中的垃圾对象全部清理掉,这样的话在回收过程就会不断空出来新的Region,一旦空闲出来的Region数量达到了堆内存的5%,此时就会立即停止混合回收,意味着本次混合回收就结束了。
收集器的选择

什么场景适合使用G1?

  • 50%以上的堆被存活对象占用
  • 对象分配和晋升的速度变化非常大
  • 垃圾回收时间特别长,超过1秒
  • 8GB以上的堆内存(建议值)
  • 停顿时间是500ms以内

调优工具

阿里巴巴 Arthas
https://gitee.com/arthas/arthas?utm_source=alading&utm_campaign=repo
教学网址
https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn
*
Gc Easy(收费)
https://gceasy.io/

END

有时间会对此博客进行完善,此处仅仅放一些参数,供查询。

相关文章