某天脑洞大开,把怀疑的目光投向了在后台运行日志收集程序Flume,发现它的GC运行得比较狂野,于是对它的GC线程数做了限制: 修改前:15分钟内, 大于30ms的业务调用173次, 大于50ms的23次
那这个新升级的监控系统,又是怎么影响到主应用的呢?找出它与应用有交互的部分,原来对于JVM的各种线程数信息,堆内存各代的信息,每拿一个数据都会启动一次JMX Client,所以每分钟都有一秒要连拿7个数据,启动7个JMX Client。 改进方法很简单,我们自己定制了一下JMX Client,将7个数据合并在一个命令里获得,另外定制了一下JMX Client的JVM参数,将它启动的动静尽量减少。
一、启动快速,动静小。
在它们运行时,跑jps -v ,结果发现通通只有一个-Xms8m 。 还不死心,又去翻源码,JDK7在 Makefile.launcher,JDK8在CompileLaunchers.gmk,结果发现全部8M,通通8M,再没别的参数了。 有同学又从久远的记忆中想起一个-client,感觉也是比较弱气的选项,但在这个多核的64位Linux服务器上是根本无效的,一定是-server,必须是-server。
各种吃内存 各种后台线程 JIT时CPU表现狂野 GC时CPU表现狂野 那我们就从这几个方面着手。 在开始折腾前,先准备好测试手段: 首先,给工具脚本配上GC 日志参数,在GC日志里就能看到实际启动参数,GC纪录,以及运行结束时内存各代的占用。 -Xloggc:gc.log -XX: PrintGCDetails -XX: PrintGCDateStamps -XX: PrintGCApplicationStoppedTime 其次,长期跑一个 pidstat -l 1| grep xxx ,紧密监控进程的CPU消耗。 最后,jstack看线程。
6.2 设定编译级别 但编译本身就需要CPU,也需要额外的编译线程。 如果脚本只简单的跑一次,比如vjtools里的vjmxcli,建议就不要进行JIT编译了,编译完了也用不上,直接解释执行就好。禁止它:-Djava.compiler=NONE 如果脚本用于密集计算,比如vjtools里的vjmap,则建议打开多层编译,一开始就对运行到的方法进行静态编译,不用等方法被调用1万次。多层编译在JDK8默认打开,显式打开:-XX: TieredCompilation。 但打开多层编译也会导致程序运行初期有较多的编译任务,吃比较多的CPU,可以显式关掉多层编译 -XX:-TieredCompilation来对比一下,综合其带来的性能提升,脚本的运行时间的长短,以及额外的CPU支出来综合评价。 6.3 编译线程的设定 6.4 未来黑科技-AOT 看各位大大炫,但我还没玩过。
如果依然想使用并行算法,就一定要设置GC线程数,在24核机器上YGC和CMS GC的线程数默认分别是18和5,为了避免成为恶邻A君。可设为: -XX:ParallelGCThreads=4 -XX:ConcGCThreads=2
一,默认的JVM初始内存大小,在大内存的服务器上会比较大,必须设置。 二,-Xms 与 -Xmx 不等时, 自动扩张并没有想象中那么智能和合理。 三、新生代默认只有1/3堆大小,而在脚本看来新生代才是大头。 建议根据GC日志的结果,完整设置-Xms 和 -Xmx,并用-Xmn(新生代占大头) 或-XX:NewRatio=1(一半半) 来设置新生代大小。 其次,每条线程的内存,从默认1M回到256k: -xss256k 其他永久代,CodeCache的初始值还算合理,没看到特别浪费的情况不用管。
|
|