JVM 调优的工具

JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。

  • jconsole:用于对 JVM 中的内存、线程和类等进行监控;
  • jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。

常用的 JVM 调优的参数都有哪些?

  • -Xms 堆内存初始化大小,一般默认为物理内存的 1/64
  • -Xmx 堆内存最大分配空间,一般默认为物理内存的 1/4
  • -Xmn 新生代的大小
  • -XX:NewSize;新生代最小值;
  • -XX:MaxNewSize:新生代最大值;
  • -XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
  • -XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
  • –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
  • -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
  • -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
  • -XX:+PrintGC:开启打印 gc 信息;
  • -XX:+PrintGCDetails:打印 gc 详细信息。

GC 调优的两大目标是啥?

分别是最短暂停时间和吞吐量。

最短暂停时间:因为 GC 会 STW (Stop The World, GC 事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应) 暂停所有应用线程,这时候对于用户而言就等于卡顿了,因此对于时延敏感的应用来说减少 STW 的时间是关键。

吞吐量:对于一些对时延不敏感的应用比如一些后台计算应用来说,吞吐量是关注的重点,它们不关注每次 GC 停顿的时间,只关注总的停顿时间少,吞吐量高。

举个例子:

方案一:每次 GC 停顿 100 ms,每秒停顿 5 次。

方案二:每次 GC 停顿 200 ms,每秒停顿 2 次。

两个方案相对而言第一个时延低,第二个吞吐高,基本上两者不可兼得。

所以调优时候需要明确应用的目标。

GC 如何调优

  1. 现在都是分代 GC,调优的思路就是尽量让对象在新生代就被回收,防止过多的对象晋升到老年代,减少大对象的分配。
  2. 需要平衡分代的大小、垃圾回收的次数和停顿时间。
  3. 需要对 GC 进行完整的监控,监控各年代占用大小、YGC 触发频率、Full GC 触发频率,对象分配速率等等。

然后根据实际情况进行调优。

比如进行了莫名其妙的 Full GC,有可能是某个第三方库调了 System.gc。

Full GC 频繁可能是 CMS GC 触发内存阈值过低,导致对象分配不过来。

还有对象年龄晋升的阈值、survivor 过小等等,具体情况还是得具体分析,反正核心是不变的。

https://tech.meituan.com/2017/12/29/jvm-optimize.html