生成
1. 生成error 文件的路径:你可以通过参数设置-XX:ErrorFile=/path/hs_error%p.log, 默认是在java运行的当前目录[default: ./hs_err_pid%p.log]
2. 参数-XX:OnError 可以在crash退出的时候执行命令,格式是-XX:OnError=“string”, <string> 可以是命令的集合,用分号做分隔符, 可以用"%p"来取到当前进程的ID.
例如:
// -XX:OnError="pmap %p" // show memory map
// -XX:OnError="gcore %p; dbx - %p" // dump core and launch debugger
在linux中系统会fork出一个子进程去执行shell的命令,因为是用fork可能会内存不够的情况,注意修改你的 /proc/sys/vm/overcommit_memory 参数,不清楚为什么这里不使用vfork
3. -XX:+ShowMessageBoxOnError 参数,当jvm crash的时候在linux里会启动gdb 去分析和调式,适合在测试环境中使用。
什么情况下不会生成error文件
linux 内核在发生OOM的时候会强制kill一些进程, 可以在/var/logs/messages中查找
Error crash 文件的几个重要部分
a. 错误信息概要
- # A fatal error has been detected by the Java Runtime Environment:
- #
- # SIGSEGV (0xb) at pc=0x0000000000043566, pid=32046, tid=1121192256
- #
- # JRE version: 6.0_17-b04
- # Java VM: Java HotSpot(TM) 64-Bit Server VM (14.3-b01 mixed mode linux-amd64 )
- # Problematic frame:
- # C 0x0000000000043566
- #
- # If you would like to submit a bug report, please visit:
- # http://java.sun.com/webapps/bugreport/crash.jsp
- # The crash happened outside the Java Virtual Machine in native code.
- # See problematic frame for where to report the bug.
SIGSEGV 错误的信号类型
pc 就是IP/PC寄存器值也就是执行指令的代码地址
pid 就是进程id
# Problematic frame:
# V [libjvm.so+0x593045]
就是导致问题的动态链接库函数的地址
pc 和 +0x593045 指的是同一个地址,只是一个是动态的偏移地址,一个是真实运行的虚拟地址
b.信号信息
Java中在linux 中注册的信号处理函数,中间有2个参数info, ucvoid
- static void crash_handler(int sig, siginfo_t* info, void* ucVoid) {
-
- sigset_t newset;
- sigemptyset(&newset);
- sigaddset(&newset, sig);
- sigprocmask(SIG_UNBLOCK, &newset, NULL);
-
- VMError err(NULL, sig, NULL, info, ucVoid);
- err.report_and_die();
- }
寄存器的信息就保存在 (ucontext_t*)usVoid中
- siginfo:si_signo=SIGSEGV: si_errno=0, si_code=1 (SEGV_MAPERR), si_addr=0x0000000000043566
信号的详细信息,和si_addr 出错误的内存,这里对应的就是信号siginfo_t的结构体里的si_addr,内核会把导致错误的内存地址保存在用户空间的信号结构体中siginfo_t,这样在进程在注册的信号处理函数中可以拿到导致错误的地址。
c.寄存器信息
- Registers:
- RAX=0x00002aacb5ae5de2, RBX=0x00002aaaaf46aa48, RCX=0x0000000000000219, RDX=0x00002aaaaf46b920
- RSP=0x0000000042d3f968, RBP=0x0000000042d3f9c8, RSI=0x0000000042d3f9e8, RDI=0x0000000045aef9b8
- R8 =0x0000000000000f80, R9 =0x00002aaab3d30ce8, R10=0x00002aaaab138ea1, R11=0x00002b017ae65110
- R12=0x0000000042d3f6f0, R13=0x00002aaaaf46aa48, R14=0x0000000042d3f9e8, R15=0x0000000045aef800
- RIP=0x0000000000043566, EFL=0x0000000000010202, CSGSFS=0x0000000000000033, ERR=0x0000000000000014
- TRAPNO=0x000000000000000e
寄存器的信息就保存在处理函数参数 (ucontext_t*)usVoid中
在X86架构下:
- void os::print_context(outputStream *st, void *context) {
- if (context == NULL) return;
-
- ucontext_t *uc = (ucontext_t*)context;
- st->print_cr("Registers:");
- #ifdef AMD64
- st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
- st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
- st->print(", RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]);
- st->print(", RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]);
- st->cr();
- st->print( "RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]);
- st->print(", RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]);
- st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]);
- st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]);
- st->cr();
- st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
- st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
- st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]);
- st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]);
- st->cr();
- st->print( "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]);
- st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]);
- st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]);
- st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]);
- st->cr();
- st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]);
- st->print(", EFL=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]);
- st->print(", CSGSFS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_CSGSFS]);
- st->print(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]);
- st->cr();
- st->print(" TRAPNO=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_TRAPNO]);
- #else
- st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]);
- st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]);
- st->print(", ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ECX]);
- st->print(", EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDX]);
- st->cr();
- st->print( "ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_UESP]);
- st->print(", EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBP]);
- st->print(", ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESI]);
- st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]);
- st->cr();
- st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]);
- st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2);
- st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]);
- #endif // AMD64
- st->cr();
- st->cr();
-
- intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
- st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp);
- print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t));
- st->cr();
-
-
-
-
- address pc = os::Linux::ucontext_get_pc(uc);
- st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc);
- print_hex_dump(st, pc - 16, pc + 16, sizeof(char));
- }
寄存器的信息在分析出错的时候是非常重要的打印出执行附近的部分机器码
- Instructions: (pc=0x00007f48f14ef51a)
- 0x00007f48f14ef4fa: 90 90 55 48 89 e5 48 81 ec 98 9f 00 00 48 89 bd
- 0x00007f48f14ef50a: f8 5f ff ff 48 89 b5 f0 5f ff ff b8 00 00 00 00
- 0x00007f48f14ef51a: c7 00 01 00 00 00 c6 85 00 60 ff ff ff c9 c3 90
- 0x00007f48f14ef52a: 90 90 90 90 90 90 55 48 89 e5 53 48 8d 1d 94 00
在instruction 部分中会打印出部分的机器码
格式是
第一种使用udis库里带的udcli工具来反汇编
命令:
- echo '90 90 55 48 89 e5 48 81 ec 98 9f 00 00 48 89 bd' | udcli -intel -x -64 -o 0x00007f48f14ef4fa
显示出对应的汇编
第二种可以用
- objectdump -d -C libjvm.so >> jvmsodisass.dump
查找偏移地址 0x593045, 就是当时的执行的汇编,然后结合上下文,源码猜测出问题的语句。
d.寄存器对应的内存的值
- RAX=0x0000000000000000 is an unknown value
- RBX=0x000000041a07d1e8 is an oop
- {method}
- - klass: {other class}
- RCX=0x0000000000000000 is an unknown value
- RDX=0x0000000040111800 is a thread
- RSP=0x0000000041261b88 is pointing into the stack for thread: 0x0000000040111800
- RBP=0x000000004126bb20 is pointing into the stack for thread: 0x0000000040111800
- RSI=0x000000004126bb80 is pointing into the stack for thread: 0x0000000040111800
- RDI=0x00000000401119d0 is an unknown value
- R8 =0x0000000040111c40 is an unknown value
- R9 =0x00007f48fcc8b550: <offset 0xa85550> in /usr/java/jdk1.6.0_30/jre/lib/amd64/server/libjvm.so at 0x00007f48fc206000
- R10=0x00007f48f8ca7d41 is an Interpreter codelet
- method entry point (kind = native) [0x00007f48f8ca7ae0, 0x00007f48f8ca8320] 2112 bytes
- R11=0x00007f48fc98f270: <offset 0x789270> in /usr/java/jdk1.6.0_30/jre/lib/amd64/server/libjvm.so at 0x00007f48fc206000
- R12=0x0000000000000000 is an unknown value
- R13=0x000000041a07d1e8 is an oop
- {method}
- - klass: {other class}
- R14=0x000000004126bb88 is pointing into the stack for thread: 0x0000000040111800
- R15=0x0000000040111800 is a thread
jvm 会通过寄存器的值对找对应的对象,也是一个比较好的参考
e. 其他的信息
error 里面还有一些线程信息,还有当时内存映像信息,这些都可以作为分析的部分参考
crash 报告可以大概的反应出一个当时的情况,特别是在没有core dump的时候,是比较有助于帮助分析的,但如果有core dump的话,最终还是core dump能快速准确的发现问题原因。
分享到:
相关推荐
这篇内容将深入探讨如何分析这些崩溃日志以及需要注意的关键点。 首先,我们可以通过设置JVM启动参数来控制崩溃日志的生成位置和行为。例如,`-XX:ErrorFile=/path/hs_error%p.log`用来指定错误日志的保存路径,...
在Java开发过程中,JVM(Java Virtual ...总之,JVM崩溃日志分析是一个细致的过程,需要结合代码、日志和各种工具来定位问题。通过深入学习和实践,开发者可以更好地理解和处理这类问题,确保Java应用的稳定运行。
"年轻代GC JVM crash"可能是因为在垃圾回收过程中遇到了严重问题,导致JVM崩溃。这可能是由于以下原因: 1. **内存溢出**:如果年轻代的空间不足以容纳新分配的对象,或者Survivor区无法容纳从Eden区晋升的对象,就...
标题"JVM Crash,生成hs_err_pid.log文件"指的是Java虚拟机在运行过程中遇到了致命问题,导致其终止运行,并自动生成了一个错误日志文件。这个文件通常位于JVM崩溃时的工作目录下,文件名由“hs_err_pid”和进程ID...
Crash崩溃日志
这将使得Java虚拟机崩溃日志被保存在$PM4H_EXTLOG/jvm目录下,并且文件名格式为jvm_crash_<模块名称>.log。 对于JBoss应用,我们可以在JBoss的配置文件中添加以下参数: JVM_CRASH_LOG="-XX:ErrorFile=$PM4H_...
5. **线程快照**:如果JVM在崩溃时能够生成线程快照,那么我们可以看到每个线程的状态(运行、等待、阻塞等),这对于分析死锁和其他多线程问题非常有价值。 解读JVM日志需要一定的经验和技术背景,但借助一些工具...
例如,在JVM crash的情况下,通常会在工作目录下自动生成一个error文件,该文件包含了crash时的详细信息,包括但不限于信号类型、错误码、问题发生的框架及堆栈信息。 在提供的案例中,可以看到JVM crash的日志信息...
- **GC日志分析**:通过设置合理的JVM参数来收集GC日志,并使用工具如GC Log Analyzer、VisualVM等分析GC行为,优化垃圾回收策略。 - **代码优化**:根据性能分析的结果,针对性地优化代码逻辑,减少不必要的对象...
1. **Java虚拟机结构**:理解JVM的内存模型是分析崩溃转储的基础。JVM内存包括堆(Heap)、方法区(Method Area)、栈(Stack)、本地方法栈(Native Method Stack)和程序计数器(PC Register)等部分,每个区域都...
2. Java 虚拟机(JVM)的故障排除:该指南提供了 JVM 故障排除的方法和步骤,包括 JVM crash 的原因分析、堆栈跟踪的获取、JVM 配置文件的编辑等。 3. Java 应用程序的故障排除:该指南介绍了 Java 应用程序的故障...
在IT行业中,Java是一种广泛应用的编程语言...综上所述,"Java开发的SHELL CRaSH.7z"可能是一个包含Java代码、Shell脚本、错误日志或其他相关资源的项目。要深入了解这个问题,我们需要解压文件并详细分析其中的内容。
java进程崩溃日志 以下为几种可能的原因: Java应用程序的问题:发生OOM导致进程Crash; JVM出错:JVM或JDK自身的Bug导致进程Crash; 被操作系统OOM-Killer;
"Crash-master"这个文件名可能指向一个项目或工具,用于研究、分析或模拟程序崩溃的情况,帮助开发者理解和解决这类问题。在实际工作中,这样的工具能够帮助我们更好地调试和优化代码,提升软件的稳定性和可靠性。
本项目"Android-CrashHandler"就是这样一个针对Android平台的自定义异常处理器,它能将崩溃日志保存到设备的SD卡上,路径为`sdcards/crash`目录下。 首先,我们来理解一下Android应用的异常处理机制。在Java语言中...
在安卓应用开发中,异常处理是一项至...在实际应用中,还可能需要考虑异常的多线程处理、崩溃报告的异步发送、错误日志的清理策略等更复杂的情况。文件"TestError"可能是模拟或测试这种自定义异常处理机制的一个用例。
首先,"cash"可能是笔误,正确的术语应该是“crash”,意为程序崩溃。Java应用崩溃通常与内存问题、线程死锁、错误的代码实现或不兼容的库有关。在JDK 1.8中,JVM(Java虚拟机)可能会由于以下原因出现奔溃: 1. **...
2. **使用工具收集数据**:基于初步的现象描述,利用各种诊断工具(如日志分析工具、监控软件等)来收集更详细的数据信息,以便于后续的分析。 3. **使用工具分析数据**:对收集到的数据进行分析,识别可能的问题...
- **JVM Crash问题诊断**:探讨导致JVM崩溃的常见原因,如OutOfMemoryError等,并学习如何通过日志文件和其他诊断工具定位问题。 通过本次实验,参与者不仅能深入理解WebSphere应用服务器的工作原理和潜在问题,还...