Java 虚拟机外部发生崩溃

你正在放松地享受 Minecraft 游戏,突然“Java 运行时环境检测到致命错误”!


book cover
照片由 Cindy Tang 提供


Java 应用程序中的致命错误

任何 Java 应用程序都可能导致致命错误。要查找提示,您需要查看生成的 hs_err 文件。以下是 运行 Minecraft 时发生的崩溃 示例。

#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000022051066, pid=2372, tid=0x00000000000017a0
#
# JRE version: Java(TM) SE Runtime Environment (8.0_172-b11) (build 1.8.0_172-b11)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.172-b11 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C [OpenAL64.dll+0x11066]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

真的是 JVM 崩溃了吗?

在责怪 JVM 并向 java.com 提交错误报告之前,您需要确保真的是 Java 运行时导致了崩溃。实际上,就在错误报告链接下方,如果您看到消息:“崩溃发生在 Java 虚拟机外部的本机代码中”,则明确表明崩溃是由其他代码(很可能是某种库)而不是 Java 虚拟机引起的。

崩溃发生在 Java 虚拟机外部

hs_err 文件中进一步搜索,您应该会看到字符串“查看有问题的帧以报告错误的位置”,这表明您应该在文件中向上查找以查明问题。

…
# Problematic frame:
# C [OpenAL64.dll+0x11066]
…

查看有问题的帧,我们发现崩溃发生在 OpenAL64.dll 中,这是 Minecraft 用于处理声音的库。

堆栈跟踪

我们可以通过查看堆栈跟踪进一步分析崩溃的原因。

…
Stack: [0x000000002bf80000,0x000000002c080000], sp=0x000000002c07e980, free space=1018k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [OpenAL64.dll+0x11066]
C [OpenAL64.dll+0x1248f]
C 0x0000000005788c67

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j org.lwjgl.openal.ALC10.nalcCreateContext(JJ)J+0
j org.lwjgl.openal.ALC10.alcCreateContext(Lorg/lwjgl/openal/ALCdevice;Ljava/nio/IntBuffer;)Lorg/lwjgl/openal/ALCcontext;+8
j org.lwjgl.openal.AL.init(Ljava/lang/String;IIZZ)V+69
j org.lwjgl.openal.AL.create(Ljava/lang/String;IIZZ)V+246
j org.lwjgl.openal.AL.create(Ljava/lang/String;IIZ)V+5
j org.lwjgl.openal.AL.create()V+6
j paulscode.sound.libraries.LibraryLWJGLOpenAL.init()V+2
j paulscode.sound.SoundSystem.CommandNewLibrary(Ljava/lang/Class;)V+273
j paulscode.sound.SoundSystem.CommandQueue(Lpaulscode/sound/CommandObject;)Z+1206
j paulscode.sound.CommandThread.run()V+51
v ~StubRoutines::call_stub
…

我们看到有一些本机帧(前缀为 C)在 OpenAL64 DLL 中执行。对 DLL 的调用是由 LWJGL(轻量级 Java 游戏库)从 Java 代码(前缀 j)发出的,而 LWJGL 又由 paulscode.sound(Paulscode 的 3D 音频系统)调用。 ~StubRoutines::call_stub 是 JVM 的调用,用于从 C 代码调用 Java 方法。此堆栈跟踪还作为令人信服的证据,证明崩溃不是由于 JVM 本身的问题,因为唯一的 JVM 相关堆栈跟踪条目是 StubRoutines 调用。如果我们能够访问 OpenAL64.dll,或者知道如何调用它,我们就可以遍历堆栈和所涉及的代码,以可能找到错误是出现在 DLL 本身、LWJGL 代码还是音频系统库中。

摘要

JVM 崩溃可能是由外部组件引起的,这些组件可能是正在运行的软件直接使用或间接相关的,例如病毒防护或其他系统软件。在这些情况下,向 java.com 提交错误报告不太可能提供帮助。第一步是通过查看 hs_err 文件 中的有问题帧来找到真正的罪魁祸首,然后采取相应措施,例如向相应所有者报告问题。