为了账号安全,请及时绑定邮箱和手机立即绑定

如何快速、低成本、低扰动地运行一段Java代码

  JVM是个运行服务端应用的好VM,但如果你只是想频繁地运行一段Java写的脚本,或者在跑一些辅助性的Java程序比如监控,比如日志收集,这时候的诉求就和平日里的应用不一样了:

https://img1.sycdn.imooc.com//5b8e7bda0001829c16001068.jpg

  1. 启动快速,动静小。

  2. 低成本,节约CPU、内存和线程。

  3. 低扰动,不干扰主应用的运行。

一、从失败的取经开始

  第一时间,看看jmap,jstack们用了什么参数,结果发现通通只有一个-Xms8m (在它们运行时,跑jps -v 可见,源码级确认JDK7见Makefile.launcher,JDK8见CompileLaunchers.gmk)。

  另外,传说中的-client,在多核的Linux服务器上的也是无效的。

  下面开始自己的折腾,首先给跑的脚本配上"-Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime", 在gc.log 里就会有实际启动参数,GC日志,以及结束时打印内存各代的占用。

  其次,长期跑一个 pidstat -l 1| grep XXX 监控进程的CPU消耗

  最后,jstack一下进程,看看里面跑着多少线程,一个默认的JVM,线程数多得吓人。

二、类的加载和编译

  1 -Xverify:none

  来自优化Eclipse启动速度的经验,说关闭Java类加载验证可以加快10% -15%的启动速度。

  2 设定编译级别

  JIT编译之后的代码比解释执行字节码更快,更省CPU,但编译本身就需要CPU,也需要额外的编译线程。临时给启动脚本配上 “-XX:+PrintCompilation”,观察编译情况。

  如果脚本的代码只简单的跑一次,比如vjtools里的vjmxcli,建议就不要进行JIT编译了,编译完了也用不上,直接解释执行就好。禁止它:-Djava.compiler=NONE

  如果脚本会用于循环计算,比如vjtools里的vjmap,则建议打开多层编译,一开始就对运行到的方法进行静态编译,不用等方法被调用1万次。多层编译在JDK8默认打开,显式打开:-XX:+TieredCompilation。

  但打开多层编译也会导致程序运行初期有较多的编译任务,吃比较多的CPU,可以显式关掉多层编译 -XX:-TieredCompilation来对比一下,综合其带来的性能提升,脚本的生命周期长短,以及额外的CPU支出来综合评价。

  3 编译线程的设定

  在24核服务器上,默认有4条C1编译线程,8条C2编译线程(多层编译下),考虑到低成本原则,建议把它设到最小的-XX:CICompilerCount=2。

  4 未来黑科技-AOT

  JIT不够酷,预先把代码编译(Ahead-of-Time,AOT) 更好。 JDK9里有一个Hotspot编译器组搞的试验性的jaotc,另一个选择是GraalVM全家桶里带的 SubstrateVM ,这个支持JDK8。两者都是基于Graal,看各位大大炫,但我还没玩过。

三、GC 设置

  这些脚本,辅助进程一般不介意GC延时,建议使用吞度量最的串行收集算法 -XX:+UseSerialGC,大大减少了其他GC算法所产生的大量GC线程,保证自己GC时也不会影响到主应用。

  如果依然想使用并行算法,就一定要设置GC线程数,如果按默认值,在24核机器上YGC和CMS GC的线程数分别是18和5,一旦发生GC,将占用大量的CPU核,直接对主应用产生巨大的影响。可设为 -XX arallelGCThreads=2 -XX:ConcGCThreads=1

四、内存设置

  JVM的堆内存扩张并没有想象中那么智能,当-Xms 与 -Xmx 不等,又没有指定新生代比例时,新生代大小更是混乱。建议根据运行后的实际占用及GC日志,完整设置一个最合适的值。

  快速运行一次的脚本,老生代几乎没用,新生代可以设大些。

  -Xms96m -Xmx96m -Xmn64m

  长期运行的,则一般设为1:1。

  -Xms256m -Xmx256m -XX:NewRatio=1

  每条线程的内存从默认1M回到256k: -xss256k

  永久代也可以一设,可惜JDK7/8的参数不兼容,用java -version 拿版本号太贵了,所以如果明确了JDK版本的话可以设置,否则就算了。

五、其他

  这些脚本,免不了和数字打交道,如果不保证没有int ->Integer的autoboxing,就还是打开-XX:AutoBoxCacheMax=20000

  如果有其他更多黑科技,请大家补充。

大家可以点击加入群:【Java高级架构进阶群】:854,180,697 里面有Java高级大牛直播讲解知识点 走的就是高端路线 ,(如果你想跳槽换工作 但是技术又不够 或者工作上遇到了瓶颈 ,我这里有一个JAVA的免费直播课程 ,讲的是高端的知识点基础不好的误入哟 ,只要你有1-5年的开发经验可以加群找我要课堂链接 注意:是免费的 没有开发经验误入哦)

六、小结

  谢谢你看到这里,这篇的题材比较偏门,幽僻处可有人行。

  一段快速执行,关闭了JIT的脚本,启动命令大概长这个样子:

  -Xms96m -Xmx96m -Xmn64m -Xss256k -XX:+UseSerialGC -Djava.compiler=NONE -Xverify:none -XX:AutoBoxCacheMax=20000

  一段辅助程序,启动命令大概长这个样子

  -Xms256m -Xmx256m -XX:NewRatio=1 -Xss256k -XX:+UseSerialGC -XX:-TieredCompilation -XX:CICompilerCount=2 -Xverify:none -XX:AutoBoxCacheMax=20000

  VJTools 几个工具的启动脚本,都按这个标准重写了一下。


写在最后:欢迎留言讨论,加关注,持续更新!!!


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消