JVM的关键系统参数介绍和详细配置

前言 -XX:+PrintFlagsFinal打印参数值当你在网上兴冲冲找到一个可优化的参数时,先打印看看,它可能已经默认打开了,再找到一个,还是默认打开了...
JDK7与JDK8,甚至JDK7中的不同小版本,有些参数值都不一样,所以不要轻信网上任何文章,一切以生产环境同版本的JDK打出来的为准 。
经常以类似下面的语句去查看参数,偷懒不起应用,用-version代替 。有些参数设置后会影响其他参数,所以也得带上 。

 
JAVA -XX:+UseConcMarkSweepGC -XX:+PrintFlagsFinal -version| grep GCThreads
对于不同版本里的默认值,建议是顺势而为,JDK在那个版本默认打开不打开总有它的理由 。安全第一,没有很好的因由,不要随便因为网上某篇文章的推荐(包括你现在在读的这篇)就去设置 。
 
JVM的关键系统参数介绍和详细配置

文章插图
 
1. 性能篇1.1 建议的性能参数1. 取消偏向锁: -XX:-UseBiasedLocking
JDK1.6开始默认打开的偏向锁,会尝试把锁赋给第一个访问它的线程,取消同步块上的synchronized原语 。如果始终只有一条线程在访问它,就成功略过同步操作以获得性能提升 。
但一旦有第二条线程访问这把锁,JVM就要撤销偏向锁恢复之前的状态,如果打开安全点日志,可以看到不少RevokeBiasd的纪录,像GC一样Stop The World的干活,虽然只是很短的停顿,但对于多线程并发的应用,取消掉它反而有性能的提升,所以Cassandra就取消了它 。
2. 加大Integer Cache: -XX:AutoBoxCacheMax=20000
Integer i=3;这语句有着 int自动装箱成Integer的过程,JDK默认只缓存 -128 ~ +127的Integer 和 Long,超出范围的数字就要即时构建新的Integer对象 。设为20000后,我们应用的QPS有足足4%的提升 。为什么是2万呢,因为-XX:+AggressiveOpts里也是这个值 。详见《Java Integer(-128~127)值的==和equals比较产生的思考》 。
3. 启动时访问并置零内存页面: -XX:+AlwaysPreTouch
启动时就把参数里说好了的内存全部舔一遍,可能令得启动时慢上一点,但后面访问时会更流畅,比如页面会连续分配,比如不会在晋升老生代时才去访问页面使得GC停顿时间加长 。ElasticSearch和Cassandra都打开了它 。
4. SecureRandom生成加速: -Djava.security.egd=file:/dev/./urandom
此江湖偏方原因是Tomcat的SecureRandom显式使用SHA1PRNG算法时,初始因子默认从/dev/random读取会存在堵塞 。额外效果是SecureRandom的默认算法也变成更合适的SHA1了 。详见 《SecureRandom的江湖偏方与真实效果》
1.2 可选的性能参数1. -XX:+PerfDisableSharedMem
Cassandra家的一个参数,一直没留意,直到发生高IO时的JVM停顿 。原来JVM经常会默默的在/tmp/hperf 目录写上一点statistics数据,如果刚好遇到PageCache刷盘,把文件阻塞了,就不能结束这个Stop the World的安全点了 。
禁止JVM写statistics数据的代价,是jps和jstat 用不了,只能用JMX,而JMX取新老生代的使用百分比还真没jstat方便,VJTools的vjmxcli弥补了这一点 。详见《The Four Month Bug: JVM statistics cause garbage collection pauses》
2. -XX:-UseCounterDecay
禁止JIT调用计数器衰减 。默认情况下,每次GC时会对调用计数器进行砍半的操作,导致有些方法一直温热,永远都达不到触发C2编译的1万次的阀值 。
3. -XX:-TieredCompilation
多层编译是JDK8后默认打开的比较骄傲的功能,先以C1静态编译,采样足够后C2编译 。
但我们实测,性能最终略降2%,可能是因为有些方法C1编译后C2不再编译了 。应用启动时的偶发服务超时也多了,可能是忙于编译 。所以我们将它禁止了,但记得打开前面的-XX:-UseCounterDecay,避免有些温热的方法永远都要解释执行 。
 
1.3 不建议的性能参数1. -XX:+AggressiveOpts
一些还没默认打开的优化参数集合, -XX:AutoBoxCacheMax是其中的一项 。但如前所述,关键系统里不建议打开 。虽然通过-XX:+AggressiveOpts 与 -XX:-AggressiveOpts 的对比,目前才改变了三个参数,但为免以后某个版本的JDK里默默改变更多激进的配置,还是不要打开了 。
2. JIT Compile相关的参数,函数调用多少次之后开始编译的阀值,内联函数大小的阀值等等,不要乱改 。
3. -server,在64位多核的linux中,你想设成-client都不行的,所以写了也是白写 。
JVM的关键系统参数介绍和详细配置

文章插图
 
2. 内存与GC篇2.1 GC策略为了稳健,还是8G以下的堆还是CMS好了,G1现在虽然是默认了,但其实在小堆里的表现也没有比CMS好,还是JDK11的ZGC引人期待 。


推荐阅读