情景
在一次项目升级过程中,需要替换一个jar包,已经有进程用这个jar包启动运行了。
操作
当没有终止这些进程的情况下,热替换该jar包
现象
替换jar包之后,在运行的进程全部消失了,打印出jvm crash的日志。
原因
查找相关资料后发现是因为java读取jar包时,为了提高性能,默认使用了mmap,也就是文件到内存的映射,使用mmap是调用的本地方法,当jar包替换后如果又触发类加载就有可能导致异常,而jvm没法控制本地方法,从而导致jvm crash。
解决方案
使用该参数关闭mmap
-Dsun.zip.disableMemoryMapping=true
但是该参数只能保证jvm不crash,但是热替换jar包后,当有些类需要加载的时候还是可能导致异常。所以该方法只是不让jvm崩溃而已,想要真正解决的话就不要在进程在执行的时候替换jar包。
总结
其实不仅仅时热替换jar包,如果在zip包读的时候更改该zip包,也有可能导致jvm crash。应该时jdk1.9之后会把mmap部分的代码用java实现来解决jvm crash的问题。
最后附上oracle官网上的解释:
Disabling mmap
Usage (on Solaris or Linux)
This release includes a new system property, sun.zip.disableMemoryMapping
, which allows the user to disable the mmap
usage in Sun's java.util.zip.Zipfile
implementation (on Solaris and Linux platforms). Solaris or Linux applications that use java.util.zip.ZipFile
may experience a SIGBUS
VM crash if the application accidentally overwrites any zip or jar files that are still being used by the same Java runtime. Although this is a programming error of the offending application, this system property provides a solution to avoid the VM crash. With the property set to true (-Dsun.zip.disableMemoryMapping=true
, or simply -Dsun.zip.disableMemoryMapping
) the Sun JDK/JRE runtime disables the mmap
usage and the VM crash that might otherwise occur by overwriting the jar or zip file can be avoided.
详情见:http://www.oracle.com/technetwork/java/javase/documentation/overview-156328.html#6u21-rev-b09