翻译于《Troubleshooting Guide for JavaSE6 with HotSpotVM》

1. 生成位置

-XX:ErrorFile=/fullpath/file,file里可以包含%p表示进程id。如果没声明,默认的名字是hs_err_pid.log,保存在进程的工作目录。如果因为权限和空间等问题不能存在工作目录,会保存在系统的临时目录


2. 包含信息

导致fatal error的操作异常或signal

版本和配置信息

导致fatal error的线程和堆栈

正在执行的线程及其状态

堆的summary

加载的native library

命令行参数

环境变量

操作系统和CPU细节


3. Header

SIGSEGV (0xb) at pc=0x417789d7, pid=21139, tid=1024

|         |            |           |          +--- thread id

|         |            |           +------------- process id

|         |            +--------------------------- program counter

|         |            (instruction pointer)

|         +--------------------------------------- signal number

+---------------------------------------------- signal name

还有可能是internal error等

“EXCEPTION_STACK_OVERFLOW”意味着这是个栈溢出的错误。

“EXCEPTION_ACCESS_VIOLATION ”意味着Java应用Crash的时候,正在运行JVM自己的代码,而不是外部的Java代码或其他类库代码。


导致error的frame

# Problematic frame:

# C [libNativeSEGV.so+0x9d7]


Frame   Type Description

 C       Native C frame

 j       Interpreted Java frame

 V       VM frame

 v       VM generated stub frame

 J       Other frame types, including compiled Java frame


4. 线程信息

Current thread (0x0805ac88): JavaThread "main " [_thread_in_native, id=21139]

|                   |                      |            |              +-- ID

|                   |                      |            +------------- state

|                   |                      +-------------------------- name

|                   +------------------------------------ type

+-------------------------------------------------- pointer


线程类型可能有:

JavaThread

VMThread

CompilerThread

GCTaskThread

WatcherThread

ConcurrentMarkSweepThread


线程状态

Thread State Description

_thread_uninitialized Thread is not created. This occurs only in the case of memorycorruption.

_thread_new Thread has been created but it has not yet started.

_thread_in_native Thread is running native code. The error is probably a bug in nativecode.

_thread_in_vm Thread is running VM code.

_thread_in_Java Thread is running either interpreted or compiled Java code.

_thread_blocked Thread is blocked.


siginfo:

在Solaris OS和Linux signal number ( si_signo ) 和 signal code (si_code)用于标示错误信息:

siginfo:si_signo=11, si_errno=0, si_code=1, si_addr=0x00004321


寄存器信息

机器指令

线程堆栈

可能有native和java两种


两个例子:

内存回收引起的Crash内存回收引起的Crash有以下的特点:在日志文件头一般有“ EXCEPTION_ACCESS _VIOLATION”和“# Problematic frame: # V [jvm.dll+....”的信息

Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)

V [jvm.dll+0x15e87e]

VM_Operation (0x063efbac): full generation collection, mode: safepoint, requested by thread 0x040f83f8

可以看到JVM正在做 “full generation collection”。另外还有可能看到,其他的回收行为:

generation collection for allocation

full generation collection

parallel gc failed allocation

parallel gc failed permanent allocation

parallel gc system gc

栈溢出引起的Crash

Java代码引起的栈溢出,通常不会引起JVM的Crash,而是抛出一个Java异常:java.lang.StackOverflowError。

但是在Java虚拟机中,Java的代码和本地C或C++代码公用相同的Stack。这样,在执行本地代码所造成的栈溢出,

就有可能引起JVM的Crash了。

栈溢出引起的Crash会在日志的文件头中看到“EXCEPTION_STACK_OVERFLOW”字样。另外,在当前线程的Stack

信息中也能发现一些信息。例如下面的例子:

-----------------------------------------------------------------------------------

# An unexpected error has been detected by HotSpot Virtual Machine:

#

# EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x10001011, pid=296, tid=2940

#

# Java VM: Java HotSpot(TM) Client VM (1.6-internal mixed mode, sharing)

# Problematic frame:

#

C [App.dll+0x1011]

#

--------------- T H R E A D ---------------

Current thread (0x000367c0): JavaThread "main" [_thread_in_native, id=2940]

:

Stack: [0x00040000,0x00080000), sp=0x00041000, free space=4k

Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)

C [App.dll+0x1011]

C [App.dll+0x1020]

C [App.dll+0x1020]

:

C [App.dll+0x1020]

C [App.dll+0x1020]

...<more frames>...

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)

j Test.foo()V+0

j Test.main([Ljava/lang/String;)V+0

v ~StubRoutines::call_stub

--------------------------------------------------------------------------------

在上面的信息中,可以发现这是个栈溢出的错误。并且当前栈剩余的空间已经很小了(free space =4k)。

因此建议将JVM的Stack的尺寸调大,主要设计两个参数:“-Xss” 和“-XX:StackShadowPages=n”。

但是,将栈的尺寸调大,也意味着在有限的内存资源中,能打开的最大线程数会减少。

5. 进程信息:线程列表和内存使用情况

VMState:虚拟机状态

General VM State Description

not at a safepoint Normal execution.

at safepoint All threads are blocked in the VM waiting for a special VM operation tocomplete.

synchronizing A special VM operation is required and the VM is waiting for all threads in the VM to block.


堆信息:


虚拟机参数和环境变量


6. 系统信息

操作系统、cpu、内存配置



比较牛逼的错误定位:

1. 查看hs_err_pidXXXX.log中的ESP,EBP等信息,以及Top of Stack的信息确定调用堆栈,找到入口地址

2. 查看hs_err_pidXXXX.log中的dll加载信息,确定dll的加载地址,使用入口地址-加载地址可得到函数的偏移

3. 使用objdump或者反汇编工具,用dll的基址+偏移定位dll中的代码,基本上就可以找到出现问题的位置。