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 如何调优
- 现在都是分代 GC,调优的思路就是尽量让对象在新生代就被回收,防止过多的对象晋升到老年代,减少大对象的分配。
- 需要平衡分代的大小、垃圾回收的次数和停顿时间。
- 需要对 GC 进行完整的监控,监控各年代占用大小、YGC 触发频率、Full GC 触发频率,对象分配速率等等。
然后根据实际情况进行调优。
比如进行了莫名其妙的 Full GC,有可能是某个第三方库调了 System.gc。
Full GC 频繁可能是 CMS GC 触发内存阈值过低,导致对象分配不过来。
还有对象年龄晋升的阈值、survivor 过小等等,具体情况还是得具体分析,反正核心是不变的。