(转)浅析JVM崩溃的原因及解决方法
崩溃错误信息如下:
- # ?#?An?unexpected?error?has?been?detected?by?HotSpot?Virtual?Machine: ?
- # ?#??EXCEPTION_ACCESS_VIOLATION?(0xc0000005)?at?pc=0x009fcf52,?pid=4752,?tid=4440?
- # ?#?Java?VM:?Java?HotSpot(TM)?Client?VM?(1.5.0_14-b03?mixed?mode) ?
- #?Problematic?frame: ?#?V??[jvm.dll+0x9cf52] ?
- # ?#?An?error?report?file?with?more?information?is?saved?as?hs_err_pid4752.log ?
- # ?#?If?you?would?like?to?submit?a?bug?report,?please?visit: ?
- #???http://java.sun.com/webapps/bugreport/crash.jsp ?#?
我只不过是想通过C++生成一个Java的Date对象,然后输出当前时间。通过这点错误信息我们大概可以知道的是
JVM crash了,输出错误到hs_err_pid4752.log日志。
结果运行死活都报这个错,也产生了一个log错误日志。其实运行一次产生一个,错都一样,我只举其中一个:
为了防止本机信息泄露,我把路径屏掉。
- # ?#?An?unexpected?error?has?been?detected?by?HotSpot?Virtual?Machine: ?
- # ?#??EXCEPTION_ACCESS_VIOLATION?(0xc0000005)?at?pc=0x009fcf52,?pid=4344,?tid=5876?
- # ?#?Java?VM:?Java?HotSpot(TM)?Client?VM?(1.5.0_14-b03?mixed?mode) ?
- #?Problematic?frame: ?#?V??[jvm.dll+0x9cf52] ?
- # ??
- ---------------??T?H?R?E?A?D??--------------- ??
- Current?thread?(0x00823d30):??JavaThread?"main"?[_thread_in_vm,?id=5876] ??
- siginfo:?ExceptionCode=0xc0000005,?reading?address?0x00000000 ??
- Registers: ?EAX=0x00000000,?EBX=0x06f8c0f8,?ECX=0x0006f954,?EDX=0x00823df0?
- ESP=0x0006f934,?EBP=0x0006f980,?ESI=0x0006f954,?EDI=0x0006f9e8?EIP=0x009fcf52,?EFLAGS=0x00010246?
- ?Top?of?Stack:?(sp=0x0006f934) ?
- 0x0006f934:???009eb893?00000000?00823d30?009ecac3 ?0x0006f944:???00823d30?00000000?0006f9fc?0006f998 ?
- 0x0006f954:???00823df0?0082b438?009a1e20?00823d30 ?0x0006f964:???0006f980?009ebb6a?00823d30?0000000e ?
- 0x0006f974:???00000004?0006f9e8?0006f998?0006f9e8 ?0x0006f984:???1000148b?00823df0?0082b434?00000000 ?
- 0x0006f994:???0006f9fc?0006fa5c?06f8c0f8?06f8c0f8 ?0x0006f9a4:???cccccccc?cccccccc?cccccccc?cccccccc? ?
- ?Instructions:?(pc=0x009fcf52) ?
- 0x009fcf42:???44?24?04?24?fc?8b?00?8b?00?c3?8b?44?24?04?24?fc ?0x009fcf52:???8b?00?ff?74?24?04?8b?c8?e8?93?fe?ff?ff?c3?8b?44? ?
- ??
- Stack:?[0x00030000,0x00070000),??sp=0x0006f934,??free?space=254k?Native?frames:?(J=compiled?Java?code,?j=interpreted,?Vv=VM?code,?C=native?code) ?
- V??[jvm.dll+0x9cf52] ?C??[NativeCode.dll+0x148b] ?
- C??[NativeCode.dll+0x1253] ?j??com.sy.test.TestNative.sayHello()V+0 ?
- j??com.sy.test.TestNative.main([Ljava/lang/String;)V+22 ?v??~StubRoutines::call_stub ?
- V??[jvm.dll+0x875dd] ?V??[jvm.dll+0xdfd96] ?
- V??[jvm.dll+0x874ae] ?V??[jvm.dll+0x8e6f1] ?
- C??[javaw.exe+0x14c5] ?C??[javaw.exe+0x3151] ?
- C??[kernel32.dll+0x16fd7] ??
- Java?frames:?(J=compiled?Java?code,?j=interpreted,?Vv=VM?code) ?j??com.sy.test.TestNative.sayHello()V+0 ?
- j??com.sy.test.TestNative.main([Ljava/lang/String;)V+22 ?v??~StubRoutines::call_stub ?
- ?---------------??P?R?O?C?E?S?S??--------------- ?
- ?Java?Threads:?(?=>?current?thread?) ?
- ??0x008306d0?JavaThread?"Low?Memory?Detector"?daemon?[_thread_blocked,?id=5624] ???0x0082fb30?JavaThread?"CompilerThread0"?daemon?[_thread_blocked,?id=5988] ?
- ??0x0082e8c0?JavaThread?"Signal?Dispatcher"?daemon?[_thread_blocked,?id=2400] ???0x0082de70?JavaThread?"Finalizer"?daemon?[_thread_blocked,?id=5704] ?
- ??0x0082ccf0?JavaThread?"Reference?Handler"?daemon?[_thread_blocked,?id=4240] ?=>0x00823d30?JavaThread?"main"?[_thread_in_vm,?id=5876] ?
- ?Other?Threads: ?
- ??0x0082a060?VMThread?[id=1960] ???0x00831270?WatcherThread?[id=5708] ?
- ?VM?state:not?at?safepoint?(normal?execution) ?
- ?VM?Mutex/Monitor?currently?owned?by?a?thread:?None ?
- ?Heap ?
- ?def?new?generation???total?576K,?used?209K?[0x02de0000,?0x02e80000,?0x032c0000) ???eden?space?512K,??40%?used?[0x02de0000,?0x02e14510,?0x02e60000) ?
- ??from?space?64K,???0%?used?[0x02e60000,?0x02e60000,?0x02e70000) ???to???space?64K,???0%?used?[0x02e70000,?0x02e70000,?0x02e80000) ?
- ?tenured?generation???total?1408K,?used?0K?[0x032c0000,?0x03420000,?0x06de0000) ????the?space?1408K,???0%?used?[0x032c0000,?0x032c0000,?0x032c0200,?0x03420000) ?
- ?compacting?perm?gen??total?8192K,?used?1715K?[0x06de0000,?0x075e0000,?0x0ade0000) ????the?space?8192K,??20%?used?[0x06de0000,?0x06f8cdb0,?0x06f8ce00,?0x075e0000) ?
- No?shared?spaces?configured. ??
- Dynamic?libraries: ?0x00400000?-?0x0040d000??******************************* ?
- ?0x7c920000?-?0x7c9b4000??C:\WINDOWS\system32\ntdll.dll ?
- 0x7c800000?-?0x7c91d000??C:\WINDOWS\system32\kernel32.dll ?0x77da0000?-?0x77e49000??C:\WINDOWS\system32\ADVAPI32.dll ?
- 0x77e50000?-?0x77ee2000??C:\WINDOWS\system32\RPCRT4.dll ?0x77fc0000?-?0x77fd1000??C:\WINDOWS\system32\Secur32.dll ?
- 0x77d10000?-?0x77d9f000??C:\WINDOWS\system32\USER32.dll ?0x77ef0000?-?0x77f38000??C:\WINDOWS\system32\GDI32.dll ?
- 0x77be0000?-?0x77c38000??C:\WINDOWS\system32\MSVCRT.dll ?0x76300000?-?0x7631d000??C:\WINDOWS\system32\IMM32.DLL ?
- 0x62c20000?-?0x62c29000??C:\WINDOWS\system32\LPK.DLL ?0x73fa0000?-?0x7400b000??C:\WINDOWS\system32\USP10.dll ?
- 0x6d710000?-?0x6d723000??C:\PROGRA~1\KASPER~1\KASPER~1\mzvkbd.dll ?0x76bc0000?-?0x76bcb000??C:\WINDOWS\system32\PSAPI.DLL ?
- 0x6d730000?-?0x6d743000??C:\PROGRA~1\KASPER~1\KASPER~1\mzvkbd3.dll ?0x6d020000?-?0x6d035000??C:\PROGRA~1\KASPER~1\KASPER~1\adialhk.dll ?
- 0x77f40000?-?0x77fb6000??C:\WINDOWS\system32\SHLWAPI.dll ?0x6d4c0000?-?0x6d4c6000??C:\PROGRA~1\KASPER~1\KASPER~1\kloehk.dll ?
- 0x00960000?-?0x00afe000??******************************* ??
- 0x76b10000?-?0x76b3a000??C:\WINDOWS\system32\WINMM.dll ?0x6d290000?-?0x6d298000?******************************* ?
- ?0x6d610000?-?0x6d61c000??******************************* ?
- ?0x6d310000?-?0x6d32d000?******************************* ?
- ?0x6d630000?-?0x6d63f000??******************************* ?
- ?0x10000000?-?0x1004e000??******************************* ?
- ?VM?Arguments: ?
- java_command:?com.sy.test.TestNative ?Launcher?Type:?SUN_STANDARD ?
- ?Environment?Variables: ?
- JAVA_HOME=******************************* ??
- CLASSPATH=******************************* ?PATH=******************************* ?
- USERNAME=user?OS=Windows_NT?
- PROCESSOR_IDENTIFIER=x86?Family?6?Model?14?Stepping?8,?GenuineIntel ??
- ??
- ---------------??S?Y?S?T?E?M??--------------- ??
- OS:?Windows?XP?Build?2600?Service?Pack?2 ??
- CPU:total?1?(cores?per?cpu?1,?threads?per?core?1)?family?6?model?14?stepping?8,?cmov,?cx8,?fxsr,?mmx,?sse,?sse2 ??
- Memory:?4k?page,?physical?1300464k(465904k?free),?swap?3092560k(2157304k?free) ??
- vm_info:?Java?HotSpot(TM)?Client?VM?(1.5.0_14-b03)?for?windows-x86,?built?on?Oct??5?2007?01:21:52?by?"java_re"?with?MS?VC++?6.0?
看到就些错误日志就可以断定是由于我用Java的主函数调用本地dll文件时出了错。
我初步推断是因为我的C++产生Java对象传给Java类后,没有回收。导致内存泄露。
?
Java的应用有时候会因为各种原因Crash,这时候会产生一个类似java_errorpid.log的错误日志。可以拿到了
这个日志,怎样分析Crash的原因呢?下面我们来详细讨论如何分析java_errorpid.log的错误日志。
一. 如何得到这个日志文件
如果有一个严重的错误引起Java进程非正常退出,我们叫Crash,这时候会产生一个日志文件。缺省情况下,这个
文件会产生在工作目录下。但是,可以在Java启动参数通过下面的设置,来改变这个文件的位置和命名规则。例如:
java -XX:ErrorFile=/var/log/java/java_error_%p.log
就将这个错误文件放在/var/log/java下,并且以java_error_pid.log的形式出现。
二.产生错误的原因
造成严重错误的原因有多种可能性。Java虚拟机自身的Bug是原因之一,但是这种可能不是很大。在绝大多数情况下,是由于系统的库文件、API或第三方的库文件造成的;系统资源的短缺也有可能造成这种严重的错误。在发生了Crash之后,如果无法定位根本原因,也应该迅速找到Work Around的方法。
三.对日志文件的分析
首先要检查日志的文件头:例如,下面是从一个客户发过来的错误日志的文件头
- ------------------------------------- ?# ?
- #?An?unexpected?error?has?been?detected?by?HotSpot?Virtual?Machine: ?# ?
- #?EXCEPTION_ACCESS_VIOLATION?(0xc0000005)?at?pc=0x0815e87e,?pid=7268,?tid=4360?# ?
- #?Java?VM:?Java?HotSpot(TM)?Server?VM?(1.4.2_13-b06?mixed?mode) ?#?Problematic?frame: ?
- #?V?[jvm.dll+0x15e87e] ?# ?
- --------------------------------------?
文件头中有很多有用的信息,“EXCEPTION_ACCESS_VIOLATION ”意味着Java应用Crash的时候,正在运行JVM自己的代码,而不是外部的Java代码或其他类库代码。这种情况很可能是JVM的Bug,但是也不一定。除了“EXCEPTION_ACCESS_VIOLATION ”,还有可能是别的信息,例如“SIGSEGV(0xb)”,意味着JVM正在执行本地或JNI的代码;“EXCEPTION_STACK_OVERFLOW”意味着这是个栈溢出的错误。(**********看到这里我们知道我报错时正在运行JVM自己的代码,而不是外部的Java代码或其他类库代码*********)
另外一个有用的JVM崩溃信息就是:
- #?Problematic?frame: ?#?V?[jvm.dll+0x15e87e]?
它说明Crash的时候,JVM正在从哪个库文件执行代码。除了“V”以外,还有可能是“C”、“j”、“v”、“J”。具体的表示意思如下:
- FrameType?Description: ?C:?Native?C?frame ?
- j:?Interpreted?Java?frame ?V:?VMframe ?
- v:?VMgenerated?stub?frame ?J:?Other?frame?types,?including?compiled?Java?frames ?
- ?(**********看到这里我们知道我报错时是V:?VMframe这种情况*********)?
文件头之后,是当前线程的DUMP信息,线程之后是JVM进程的DUMP信息,包括所有线程的状态、地址和ID。最后还有JVM状态,
Heap状态,动态连接库等等的信息。这些烦乱的信息中,包含有非常有用的信息。下面我们根据几个具体的实例来分析JVM崩溃的典型例子。
四.内存回收引起的Crash
内存回收引起的Crash有以下的特点:在日志文件头一般有“ EXCEPTION_ACCESS _VIOLATION”和
“# Problematic frame: # V [jvm.dll+....”的信息,意味着这是在JVM内部处理,而且多半是JVM的Bug。
(**********看到这里我们知道我报错时意味着这是在JVM内部处理,而且多半是JVM的Bug*********)
对于这类问题,最快的方法就是绕过它。
另外,在Thread的DUMP信息最后,还能看到有关内存回收的行为例如:
- ---------------?T?H?R?E?A?D?--------------- ?Current?thread?(0x00a56668):?VMThread?[id=4360] ?
- siginfo:?ExceptionCode=0xc0000005,?reading?address?0x00000057 ?Registers: ?
- ........ ??
- Stack:?[0x03cf0000,0x03d30000),?sp=0x03d2fc18,?free?space=255k?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 ?(***********这些错,俺都没碰到***********)?
采取改变回收的算法和参数的方法来绕过去。例如,来自客户的日志除了上面的日志信息,在日志中Heap信息中还能发现一些其他信息:
- -------------------------- ?Heap ?
- def?new?generation?total?22592K,?used?19530K?[0x10010000,?0x11890000,?0x138f0000) ?eden?space?20096K,?97%?used?[0x10010000,?0x11322bd8,?0x113b0000) ?
- from?space?2496K,?0%?used?[0x113b0000,?0x113b0000,?0x11620000) ?to?space?2496K,?0%?used?[0x11620000,?0x11620000,?0x11890000) ?
- tenured?generation?total?190696K,?used?100019K?[0x138f0000,?0x1f32a000,?0x30010000) ?the?space?190696K,?52%?used?[0x138f0000,?0x19a9cf38,?0x19a9d000,?0x1f32a000) ?
- compacting?perm?gen?total?38656K,?used?38588K?[0x30010000,?0x325d0000,?0x34010000) ?the?space?38656K,?99%?used?[0x30010000,?0x325bf038,?0x325bf200,?0x325d0000) ?
- ----------------------------?
上面的信息能看出在Crash的时候,JVM的PermSize空间几乎已经消耗完了,并且回收算法在压缩Perm空间的时候出了错。因此,建议改变内存回收的算法,或扩大PermSize和MaxPermSize的数值。
(*******这个倒是可以尝试*******)
五.栈溢出引起的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] ?
- ...... ?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”。但是,将栈的尺寸调大,也意味着在有限的内存资源中,能打开的最大线程数会减少。(******俺的栈剩余还有free space=254k,显然不符,于是乎我决定假期再解决,o(∩_∩)o...******)
JVM崩溃的原因及解决方法结论:
我觉得还是C++建立Java对象后,没有回收。鉴定完毕