阿里版JVM

很多人已经知道,阿里广泛使用Java技术。由于阿里对Java使用的广泛和深入,以至于阿里开始了自己的JVM实践。业界中Twitter也有JVM的定制优化实践,但细节不太了解。2010年开始,阿里核心系统部专用计算组基于OpenJDK6 Hotspot JVM定制优化自己的JVM,经过几次双11的考验。2013年开始,改为基于OpenJDK7,并改名为阿里JVM,阿里JVM是开源的,感兴趣的可以点击此查看

 

Alibaba Dragonwell8 JDK 开源地址:  https://github.com/alibaba/dragonwell8 

 

JVM简介

JVM,Java虚拟机,是执行Java字节码的虚拟机。有关JVM、Java运行环境JRE和Java开发包JDK的关系可以参考这个页面(http://docs.oracle.com/javase/7/docs/)的图片,很直观。粗粗地说,Hotspot JVM解释运行Java字节码。解释运行的同时发现热点,JIT编译器将热点编译为机器码,这是在现代JVM上运行Java,性能并不差的原因。另外JVM的另一显著的功能是自动垃圾回收,GC。示意图如下:

注意到图中还有GCIH,intrinsic,JFR,这些将在下面阿里JVM中提到。

 

定制优化解决的问题

官方JVM是一个通用产品,一大目标是尽可能的兼容各个平台和满足大部分应用场景的需求。

由于开发和维护资源有限,对于特定平台和应用场景而言,官方JVM在性能和功能上,都有取舍。

而在阿里,所使用的平台是统一的x86平台,应用也有自己的场景特点,针对平台和应用场景的极致的优化,可以做得更多。

另一方面,由于阿里的规模大,单机上每一点点进步,乘以规模,其效益都会被放大。所以值得投入资源来定制优化自己的JVM。上图中,阴影的部分就是阿里JVM定制优化的地方。

 

性能优化

首先,针对Intel X86 CPU进行JVM本身的编译优化,生成性能更高的可执行代码。即图中左边静态部分。右边动态生成部分的机器码的性能和JVM本身的编译无关,所以执行性能没有影响。可以看到静态部分中,GC是一个重要的模块。举例,编译优化后young gc性能有约20%的提高。

以上是不修改源码得到的性能提升,当然也有修改源码的。
例如:
x86_64平台下JNI native wrapper的分支整理优化;
去除Linux下无用的DTrace的钩子函数;
优化了GC的一些细节,包括并发的逻辑,卡表的逻辑。

为了获得更大的性能提升,阿里JVM还提供了针对特定需求的intrinsic,增加了:
CRC32、CRC32C;
byte数组比较、char数组比较;
ASCII转UTF8;
SpinLock pause的Intrinsic方法。

这些优化大多利用了X86的SIMD指令,使用这些新的API,虽然需要应用改代码,但是带来的局部性能提升非常大,选择这些优化点,是对应用进行性能剖析得出来的。

 

故障排查

阿里JVM积累一些故障排查经验,并在JVM中做了优化。包括:
修复一些BUG、如GC、socket连接泄漏,并提交给社区;
在crash log里输出反汇编信息,用于帮助调查crash问题;

添加ArrayAllocationWarningSize参数,当应用申请超大数组,会打印警告,这个功能帮助排查了一些诡异的应用问题,很实用;

添加单独指定新建Java线程的栈大小的API。有些典型应用,由于某线程递归深度比较深栈溢出。调线程栈参数是全局的,对于大部分线程是浪费内存,单独指定可以解决;

添加PrintGCReason参数;将PrintJNIGCStalls、DisableExplicitGC与ExplicitGCInvokesConcurrent参数改为manageable用于帮助排查、解决GC问题;

添加forceGC()与forceCompactionGC()的API,可以来缓解CMS GC碎片化的问题,应用可以选择在没有业务请求的时间段自主触发Full GC;

使用jemalloc替代glibc的ptmalloc,解决ptmalloc物理内存不释放的bug;

增加参数ReclaimMostNativeMemory以最大限度释放物理内存,当directmemory使用量达到一定值时输出预警信息并进行CMS GC,根据调用栈统计direct memory申请分布情况;

Java异常统计,对应用无侵入地统计所有异常个数以及发生次数最多的异常,用以协助诊断CPU热点,比如有应用频繁抛异常同时自己catch作为逻辑判断,对性能有较大影响;

将参数OmitStackTraceInFastThrow设为managable,如果想要排查的异常没有StackTrace,可以动态调整这个参数;

还有一个重大的定制,是加入了对Flight recorder的支持,Flight recorder源自于JRockit JVM,是一个高性能的基于事件的记录器,它可以记录下应用运行过程中JVM发生的各种行为,对于应用的问题诊断有着很大的帮助,OpenJDK Hotspot中只有Flight recorder的一些埋点,没有完整实现,阿里JVM基于OpenJDK Hotspot实现了自己的Flight recorder,即图中JFR部分,记录的事件包括:GC、线程同步、JIT、类加载和VMOperation。

对于Flight recorder的问题诊断功能,可以通过阿里内部JVM故障排查系统进行使用,同时JVM故障排查系统还提供了GC、线程dump、Crash 等日志的分析诊断功能。

最后,阿里JVM提供了一个JIT符号信息的接口,结合阿里的系统级性能剖析系统,和阿里监控平台,可以在线对线上应用低开销地进行系统级性能剖析和监控。

 

解决特定应用痛点

特定应用有GC相关痛点,我们针对这种应用,开发了GC Invisible Heap,GC不可见堆,即图中GCIH部分。

有应用有在同一机器多JVM之间共享对象的需求,有的应用有将超大文件,映射到对象的需求,业界有个Off Heap的概念,都是JVM之上的实现,基本上避免不了序列化和反序列化。

GCIH修改了JVM,直接映射Java对象,没有序列化开销。解决也应用的痛点。目前共享对象应用已经在线上稳定运行多时,超大堆压缩功能正在研发。

 

后续发展

阿里JVM的实践,除了性能优化,和定制化,很大的投入是在故障排查方面,而故障排查很多时候还需要人工经验,后续主要是想把之前积累的经验,做成服务化系统,一方面解放阿里JVM团队,去做更多研发工作,另一方面也为将来服务更多的客户,打好基础。

 

转载自:http://hellojava.info/?p=336

posted on 2018-07-11 10:29  wpjamer  阅读(5382)  评论(0编辑  收藏  举报

导航