java 在类加载期间 memcpy 时 JVM 崩溃
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1313071/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JVM crash while memcpy during class load
提问by richs
My JVM crashed the and the hs_err file showed that it crashed while attempting to load a class. Specifically while trying to memcpy ([libc.so.6+0x6aa2c] memcpy+0x1c). I looked at the .class file and was able to determine what class was being loaded.
我的 JVM 崩溃了,并且 hs_err 文件显示它在尝试加载类时崩溃了。特别是在尝试 memcpy ([libc.so.6+0x6aa2c] memcpy+0x1c) 时。我查看了 .class 文件并能够确定正在加载什么类。
But can any one tell me what could cause this or how i could determine more about the cause? If the JVM was out of memory wouldn't it throw an Error. Any insight is greatly appreciated.
但是谁能告诉我是什么原因导致了这种情况,或者我如何确定更多的原因?如果 JVM 内存不足,它不会抛出错误。任何见解都非常感谢。
I've included an excerpt from my hs_err file.
我已经包含了我的 hs_err 文件的摘录。
#
# An unexpected error has been detected by Java Runtime Environment:
#
# SIGBUS (0x7) at pc=0x005aba2c, pid=20841, tid=2427227056
#
# Java VM: Java HotSpot(TM) Client VM (1.6.0_02-b05 mixed mode)
# Problematic frame:
# C [libc.so.6+0x6aa2c] memcpy+0x1c
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#
--------------- T H R E A D ---------------
Current thread (0x90d0dc00): JavaThread "ORDERHANDLER" [_thread_in_native, id=20881]
siginfo:si_signo=7, si_errno=0, si_code=2, si_addr=0x915e3000
Registers:
EAX=0x91218298, EBX=0xb7f2e71c, ECX=0x0000079b, EDX=0x915dfef2
ESP=0x90ac6a34, EBP=0x90ac6a60, ESI=0x915e2ffd, EDI=0x914f0a0d
EIP=0x005aba2c, CR2=0x915e3000, EFLAGS=0x00010206
Top of Stack: (sp=0x90ac6a34)
0x90ac6a34: b7f29d4b 914ed930 915dff20 00004f49
0x90ac6a44: 082e7bc4 00006f6f 00004243 00004f49
0x90ac6a54: b7f2e71c 080e3e54 00000000 90ac6a90
0x90ac6a64: b7f29fbb 080e3b00 080e3e54 00000000
0x90ac6a74: 00000000 90d0dc00 00000000 d68dd1b6
0x90ac6a84: b7f2e71c 90ac6ad8 90d0dcec 90ac6f00
0x90ac6a94: b7f21169 080e3b00 90ac6ad8 0000002b
0x90ac6aa4: 0000002b 90ac6ad8 00000008 00000000
Instructions: (pc=0x005aba2c)
0x005aba1c: 8b 74 24 08 fc d1 e9 73 01 a4 d1 e9 73 02 66 a5
0x005aba2c: f3 a5 89 c7 89 d6 8b 44 24 04 c3 90 90 90 90 90
Stack: [0x90a78000,0x90ac9000), sp=0x90ac6a34, free space=314k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libc.so.6+0x6aa2c] memcpy+0x1c
C [libzip.so+0xbfbb] ZIP_GetEntry+0x10b
C [libzip.so+0x3169] Java_java_util_zip_ZipFile_getEntry+0xc9
J java.util.zip.ZipFile.getEntry(JLjava/lang/String;Z)J
J java.util.zip.ZipFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;
J java.util.jar.JarFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;
J sun.misc.URLClassPath$JarLoader.getResource(Ljava/lang/String;Z)Lsun/misc/Resource;
J sun.misc.URLClassPath.getResource(Ljava/lang/String;Z)Lsun/misc/Resource;
J java.net.URLClassLoader.run()Ljava/lang/Object;
v ~StubRoutines::call_stub
V [libjvm.so+0x20bbbd]
V [libjvm.so+0x30a6b8]
V [libjvm.so+0x20ba50]
V [libjvm.so+0x26190b]
C [libjava.so+0xaa5c] Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2+0x3
c
J java.security.AccessController.doPrivileged(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;
J java.net.URLClassLoader.findClass(Ljava/lang/String;)Ljava/lang/Class;
J java.lang.ClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;
J sun.misc.Launcher$AppClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;
j java.lang.ClassLoader.loadClass(Ljava/lang/String;)Ljava/lang/Class;+3
j java.lang.ClassLoader.loadClassInternal(Ljava/lang/String;)Ljava/lang/Class;+2
v ~StubRoutines::call_stub
V [libjvm.so+0x20bbbd]
V [libjvm.so+0x30a6b8]
V [libjvm.so+0x20b6e1]
V [libjvm.so+0x20b7ca]
V [libjvm.so+0x367621]
V [libjvm.so+0x3662a5]
V [libjvm.so+0x365357]
V [libjvm.so+0x365112]
V [libjvm.so+0x1adb03]
V [libjvm.so+0x1aeb32]
V [libjvm.so+0x2d75cb]
V [libjvm.so+0x2d8a94]
V [libjvm.so+0x2d8a17]
V [libjvm.so+0x1fe7f8]
j com.aqua.foms.book.OrderHandler.handleNewOrder(Lcom/aqua/NmsApi/OrderMap;Lcom/aqua/api/AtsMessage;)V+221
j com.aqua.foms.book.FMSNewOrderTask.execute()V+12
j com.aqua.api.EEDefaultWorkerThread.run()V+96
v ~StubRoutines::call_stub
V [libjvm.so+0x20bbbd]
V [libjvm.so+0x30a6b8]
V [libjvm.so+0x20b4d0]
V [libjvm.so+0x20b55d]
V [libjvm.so+0x27b795]
V [libjvm.so+0x383ef0]
V [libjvm.so+0x30b5a9]
C [libpthread.so.0+0x5371]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
J java.util.zip.ZipFile.getEntry(JLjava/lang/String;Z)J
J java.util.zip.ZipFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;
J java.util.jar.JarFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;
J sun.misc.URLClassPath$JarLoader.getResource(Ljava/lang/String;Z)Lsun/misc/Resource;
J sun.misc.URLClassPath.getResource(Ljava/lang/String;Z)Lsun/misc/Resource;
J java.net.URLClassLoader.run()Ljava/lang/Object;
v ~StubRoutines::call_stub
J java.security.AccessController.doPrivileged(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;
J java.net.URLClassLoader.findClass(Ljava/lang/String;)Ljava/lang/Class;
J java.lang.ClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;
J sun.misc.Launcher$AppClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;
j java.lang.ClassLoader.loadClass(Ljava/lang/String;)Ljava/lang/Class;+3
j java.lang.ClassLoader.loadClassInternal(Ljava/lang/String;)Ljava/lang/Class;+2
v ~StubRoutines::call_stub
j com.aqua.foms.book.OrderHandler.handleNewOrder(Lcom/aqua/NmsApi/OrderMap;Lcom/aqua/api/AtsMessage;)V+221
j com.aqua.foms.book.FMSNewOrderTask.execute()V+12
j com.aqua.api.EEDefaultWorkerThread.run()V+96
v ~StubRoutines::call_stub
--------------- P R O C E S S ---------------
Java Threads: ( => current thread )
0x080c9c00 JavaThread "pool-1-thread-3" [_thread_blocked, id=18725]
0x0824f800 JavaThread "pool-1-thread-2" [_thread_blocked, id=13693]
0x91217c00 JavaThread "AquaSchedulerService_7" daemon [_thread_blocked, id=23675]
0x91215c00 JavaThread "AquaSchedulerService_6" daemon [_thread_blocked, id=23001]
0x91215400 JavaThread "AquaSchedulerService_5" daemon [_thread_blocked, id=22759]
0x91213400 JavaThread "AquaSchedulerService_4" daemon [_thread_blocked, id=22410]
0x91212c00 JavaThread "AquaSchedulerService_3" daemon [_thread_blocked, id=22262]
0x08316400 JavaThread "pool-1-thread-1" [_thread_blocked, id=22260]
0x0827d000 JavaThread "JmsConn_1_sender_0" daemon [_thread_blocked, id=21196]
0x90d0cc00 JavaThread "Timer-0" [_thread_blocked, id=20882]
=>0x90d0dc00 JavaThread "ORDERHANDLER" [_thread_in_native, id=20881]
0x90d0d400 JavaThread "TradeInviteMonitor" [_thread_blocked, id=20880]
0x90d09c00 JavaThread "ROUTERT" [_thread_blocked, id=20878]
0x90d09000 JavaThread "TIBCO EMS Session Dispatcher (33197)" [_thread_blocked, id=20877]
0x08310800 JavaThread "DORDERHANDLER" [_thread_blocked, id=20874]
0x90d01c00 JavaThread "Thread-12" daemon [_thread_blocked, id=20873]
0x90d03000 JavaThread "Thread-11" daemon [_thread_in_native, id=20872]
0x082e1c00 JavaThread "DELAYEDORDMON" [_thread_blocked, id=20871]
0x082e8000 JavaThread "DBUPD" [_thread_blocked, id=20870]
0x914e5000 JavaThread "pool-2-thread-1" [_thread_blocked, id=20869]
0x914e3c00 JavaThread "StatusStatsEventDispatcherThread" [_thread_blocked, id=20868]
0x082c8400 JavaThread "TimerQueue" daemon [_thread_blocked, id=20866]
0x082ca000 JavaThread "MDATATHREAD" [_thread_blocked, id=20865]
0x082c9400 JavaThread "AquaSchedulerService_2" daemon [_thread_blocked, id=20864]
0x9122b000 JavaThread "DestroyJavaVM" [_thread_blocked, id=20843]
0x91200800 JavaThread "FirmMatchingServer" [_thread_blocked, id=20863]
0x914de800 JavaThread "TIBCO EMS TCPLink Reader (32084)" daemon [_thread_in_native, id=20861]
0x9122a400 JavaThread "TIBCO EMS Connections Pinger" daemon [_thread_blocked, id=20859]
0x914d4000 JavaThread "WDISTQ" [_thread_blocked, id=20858]
0x9121f400 JavaThread "JmsConn_1_connector_0" daemon [_thread_blocked, id=20857]
0x914d8000 JavaThread "JmsConn_1_receiver_0" daemon [_thread_blocked, id=20856]
0x9149ac00 JavaThread "AquaSchedulerService_1" daemon [_thread_blocked, id=20855]
0x9149b400 JavaThread "AquaSchedulerService_0" daemon [_thread_blocked, id=20854]
0x9142a000 JavaThread "MySQL Statement Cancellation Timer" daemon [_thread_blocked, id=20852]
0x91425c00 JavaThread "Dispatcher-Thread-0" daemon [_thread_blocked, id=20851]
0x080bf800 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=20849]
0x080bdc00 JavaThread "CompilerThread0" daemon [_thread_blocked, id=20848]
0x080bcc00 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=20847]
0x080a9800 JavaThread "Finalizer" daemon [_thread_blocked, id=20846]
0x080a8800 JavaThread "Reference Handler" daemon [_thread_blocked, id=20845]
Other Threads:
0x080a5400 VMThread [id=20844]
0x080c1000 WatcherThread [id=20850]
VM state:not at safepoint (normal execution)
VM Mutex/Monitor currently owned by a thread: None
回答by james
we've seen similar errors. our current suspect is jar files which are re-written (by an upgrade process) while the process is running.
我们见过类似的错误。我们目前的怀疑是 jar 文件,这些文件在进程运行时被重写(通过升级进程)。
回答by Stuart Caie
Answer 1 is correct. The implementation of java.util.zip.* is at fault.
答案1是正确的。java.util.zip.* 的实现有问题。
If you replace a zip/jar file that a Java program currently has "open" (has cached the ZipFile/JarFile object), it will use cached table-of-contents (TOC) data it read from the original file, and will try and use that to unpack data in the replaced file. The inflation code is not robust and will outright crash when presented with bad data.
如果您替换 Java 程序当前已“打开”(已缓存 ZipFile/JarFile 对象)的 zip/jar 文件,它将使用从原始文件中读取的缓存目录 (TOC) 数据,并将尝试并使用它来解压缩替换文件中的数据。通货膨胀代码并不健壮,当出现不良数据时会彻底崩溃。
Normal unix programs keep files open while they're working with them. If you overwrite the file, the program using it still has access to the original that it opened, by virtue of the open file descriptor.
普通的 Unix 程序在使用文件时会保持文件打开。如果您覆盖该文件,则使用它的程序仍然可以通过打开的文件描述符访问它打开的原始文件。
OpenJDK's java.util.zip.* implementation chose not to keep file descriptors open for zip/jar files. One reason for this could be that Java is often invoked with hundreds of jar files in the class path, and the designers didn't want to use up hundreds of file descriptors on the jar files alone, leaving none left for the program itself. So they close file descriptors as soon as they've read the jar/zip table of contents, and permanently lose access to the original jar/zip file, should its contents change.
OpenJDK 的 java.util.zip.* 实现选择不为 zip/jar 文件保持文件描述符打开。造成这种情况的一个原因可能是 Java 经常在类路径中使用数百个 jar 文件调用,并且设计人员不想仅在 jar 文件上使用数百个文件描述符,而不会为程序本身留下任何文件描述符。因此,一旦他们读取了 jar/zip 目录,他们就会关闭文件描述符,并且如果其内容发生更改,则永久失去对原始 jar/zip 文件的访问权限。
For whatever reason, ZipFile does not or cannot tell a zip/jar file has changed. If it did, it could re-read the TOC or throw some kind of Error if that's not possible.
无论出于何种原因,ZipFile 不会或不能告诉 zip/jar 文件已更改。如果是这样,它可以重新读取 TOC 或在不可能的情况下抛出某种错误。
Furthermore, even if the TOC remained valid, it's a problem that the inflater crashes on faulty data. What if the ZIP table-of-contents was valid but the deflated data stream was deliberately wrong?
此外,即使 TOC 仍然有效,充气器在错误数据上崩溃也是一个问题。如果 ZIP 目录有效但压缩的数据流故意错误怎么办?
Here's a test program that proves java.util.zip.* doesn't keep file descriptors open for zip/jar files and doesn't detect that the zip file has changed.
这是一个测试程序,它证明 java.util.zip.* 不会为 zip/jar 文件保持文件描述符打开,并且不会检测到 zip 文件已更改。
import java.util.zip.*;
import java.io.*;
public class ZipCrashTest {
public static void main(String args[]) throws Exception {
// create some test data
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) sb.append("Hello, World\n");
final byte[] data = sb.toString().getBytes();
// create a zip file
try (ZipOutputStream zo = new ZipOutputStream(new FileOutputStream("test1.zip"))) {
zo.putNextEntry(new ZipEntry("world.txt")); zo.write(data, 0, data.length); zo.closeEntry();
zo.putNextEntry(new ZipEntry("hello.txt")); zo.write(data, 0, data.length); zo.closeEntry();
}
// create a second valid zip file, but with different contents
try (ZipOutputStream zo = new ZipOutputStream(new FileOutputStream("test2.zip"))) {
zo.putNextEntry(new ZipEntry("hello.txt")); zo.write(data, 0, data.length); zo.closeEntry();
zo.putNextEntry(new ZipEntry("world.txt")); zo.write(data, 0, data.length); zo.closeEntry();
}
// open the zip file
final ZipFile zf = new ZipFile("test1.zip");
// read the first file from it
try (InputStream is = zf.getInputStream(zf.getEntry("hello.txt"))) {
while (is.read() != -1) { /* do nothing with the data */ }
}
// replace the contents of test1.zip with the different-but-still-valid test2.zip
Runtime.getRuntime().exec("cp test2.zip test1.zip");
// read another entry from test1.zip: it does not detect that the file has changed.
// the program will crash here
try (InputStream is = zf.getInputStream(zf.getEntry("world.txt"))) {
while (is.read() != -1) { /* do nothing */ }
}
}
}
Running this program should give you a JVM crash:
运行这个程序应该会给你一个 JVM 崩溃:
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGBUS (0x7) at pc=0x00007fb0fbbeef72, pid=4140, tid=140398238095104
...
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libzip.so+0x4f72] Java_java_util_zip_ZipFile_getZipMessage+0x1132
C [libzip.so+0x5d7f] ZIP_GetEntry+0xcf
C [libzip.so+0x3904] Java_java_util_zip_ZipFile_getEntry+0xb4
j java.util.zip.ZipFile.getEntry(J[BZ)J+0
j java.util.zip.ZipFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;+38
j ZipCrashTest.main([Ljava/lang/String;)V+476
The main bug filed against the JVM for this is JDK-4425695 : Updating jar files crashes running programs.
为此针对 JVM 提交的主要错误是JDK-4425695:更新 jar 文件会导致运行程序崩溃。
RFE 6929479: Add a system property sun.zip.disableMemoryMapping to disable mmap use in ZipFileimplements a system property in JDK7 - sun.zip.disableMemoryMapping- which you could use as a workaround.
RFE 6929479:添加系统属性 sun.zip.disableMemoryMapping 以禁用在 ZipFile 中使用 mmap在 JDK7 中实现了系统属性sun.zip.disableMemoryMapping- 您可以将其用作解决方法。
回答by Fairoz
Issue is zip/JAR file is being overwritten while in use. OpenJDK code for ZIP file format is in native C code any entry lookup, creation requires multiple round-trip of expensive jni invocations. The current native C implementation code uses mmap to map in the central directory table which is a big risk of vm crash when the underlying jar file gets overwritten with new contents while it is still being used by other ZipFile, that is what is happening. Using - Dsun.zip.disableMemoryMapping=true will solve the problem,
问题是 zip/JAR 文件在使用时被覆盖。ZIP 文件格式的 OpenJDK 代码是本机 C 代码中的任何条目查找,创建需要多次往返昂贵的 jni 调用。当前的本机 C 实现代码使用 mmap 映射到中央目录表中,当底层 jar 文件被新内容覆盖而其他 ZipFile 仍在使用它时,这是 vm 崩溃的很大风险,这就是正在发生的事情。使用 - Dsun.zip.disableMemoryMapping=true 将解决问题,
JDK9 early access builds are available that has solution for this.
可以使用 JDK9 早期访问版本来解决此问题。
Check the original issue https://bugs.openjdk.java.net/browse/JDK-8142508that has been fixed in 9 early access build 97.
检查原始问题https://bugs.openjdk.java.net/browse/JDK-8142508已在 9 早期访问版本 97 中修复。
回答by nos
Other than a plain ol. bug in the JVM(upgrade to the latest version and hope it doesn't happen again) - or some buggy 3. party libraries using JNI, there's 2 other "interesting" things that could cause this.
除了普通的ol。JVM 中的错误(升级到最新版本并希望它不会再次发生)-或使用 JNI 的一些有问题的 3. 方库,还有其他 2 个“有趣”的事情可能会导致这种情况。
Hardware failure - bad RAM is often a good candidate ot a corrupted filesystem could cause of a flaky drive could be a culprit too.
If you're running on Solaris, you can get SIGBUS errors if somehow the class/jar file was truncated just when the JVM needs to access it in the cases the JVM mmaps the jar/class file.
硬件故障 - 坏的 RAM 通常是一个很好的候选者,而损坏的文件系统可能会导致片状驱动器也可能是罪魁祸首。
如果您在 Solaris 上运行,并且在 JVM 映射 jar/class 文件的情况下,类/jar 文件以某种方式在 JVM 需要访问它时以某种方式截断,则您可能会收到 SIGBUS 错误。
回答by Nil Yueyu
I don't know if you have solved the problem because I encountered exactly the same problem. I only use mmap to map a 64KB file into a memory and use memcpy to copy data to/from the buffer. The same error occurred either when I use JNI or when I use JNA. I'm an experienced JNI programmer for years and I'm exactly implemented the same logic in a pure C program which works pretty well.
不知道你是否解决了问题,因为我遇到了完全相同的问题。我只使用 mmap 将 64KB 文件映射到内存中,并使用 memcpy 将数据复制到缓冲区/从缓冲区复制数据。当我使用 JNI 或使用 JNA 时,会发生同样的错误。我多年来一直是一名经验丰富的 JNI 程序员,并且我在一个运行良好的纯 C 程序中完全实现了相同的逻辑。
I assume it's a JDK's bug which trap some SIGs. But I really don't have time to dig it any more. For now I decided to abandon this approach and try other way to do something I wanna do.
我认为这是一个 JDK 的错误,它捕获了一些 SIG。但我真的没有时间再挖掘它了。现在我决定放弃这种方法并尝试以其他方式做我想做的事情。
If you're interested in why I'm doing this, I just wanna implement a thread safe memory mapped file in JNI. Because in JDK's implementation, the position is a global variable in ByteBuffer(which is mapped from FileChannel). I just wanna use one MemoryMappedBuffer instance to access the content in multiple threads which I've done in a C++ program.
如果您对我这样做的原因感兴趣,我只想在 JNI 中实现一个线程安全的内存映射文件。因为在JDK的实现中,位置是ByteBuffer(从FileChannel映射而来)中的一个全局变量。我只想使用一个 MemoryMappedBuffer 实例来访问我在 C++ 程序中完成的多个线程中的内容。
BTW, I'm using JDK 7 in Mac OS X 10.10.
顺便说一句,我在 Mac OS X 10.10 中使用 JDK 7。

