文章目录
最近一段时间生产环境频繁出问题,每次都会生成一个hs_err_pid*.log文件,因为工作内容的原因,之前并没有了解过相关内容,趁此机会学习下,根据项目的使用情况,此文章针对JDK 8进行分析,不过因为素材问题,文章中引用的文件内容为JDK 7生成的文件,此处应该不影响,因为官方文档中关于此部分说明使用的是JDK 6生成的文件。我们将按照内容在文件中出现的顺序进行介绍。
PS:本人水平有限,工作中也没有太多机会进行此类知识的应用,文章内容绝大多数来自于官方文档,某些内容在官网中并没有涉及,相应的介绍不一定准确,希望各位大佬不吝赐教
JDK 8
官方文档下载地址:https://www.oracle.com/java/technologies/javase-jdk8-doc-downloads.html
致命错误日志文档:/docs/technotes/guides/troubleshoot/felog.html#fatal_error_log_vm
JDK 7
官方文档地址:https://docs.oracle.com/javase/7/docs/
致命错误日志文档:https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/felog.html
文件描述
错误日志是在JVM遇到致命错误时生成的日志文件,可能包括以下信息:
- 引发致命错误的异常操作或信号
- 版本和配置信息
- 引发致命错误的线程详细信息和线程堆栈记录
- 正在运行的线程及其状态的列表
- 有关堆的概要信息
- 加载的本机库的列表
- 命令行参数
- 环境变量
- 操作系统和 CPU 的详细信息
当问题严重到错误处理器无法收集并报告所有信息时,可能只有一部分信息会写入错误日志。
文件总共分为一下几个章节:
- 简单描述崩溃信息的文件头
- 线程描述部分
- 进程描述部分
- 系统信息部分
文件位置
致命错误日志文件位置可以通过 -XX:ErrorFile
进行指定,例如:
java * -XX:ErrorFile=/var/log/java/java_error%p.log
以上设置表示文件会放在/var/log/java
目录下,%p
表示进程的PID。如果不设置XX:ErrorFile
属性,日志默认生成在执行java命令的目录下,文件名默认为hs_err_pid%p.log
,如果该目录因为某种情况无法写入(空间不足,权限不足等),在linux系统下默认写到/tmp
目录下,windows系统下默认使用环境变量中TMP
对应的目录,如果没有则使用TEMP
对应的目录(TMP和TEMP均为windows默认的环境变量,且默认值一样)。
文件头
文件头在错误日志的最开头,主要是对问题的简单描述。这部分内容同样会打印到标准输出,可能也会打印到应用程序的控制台上。示例如下:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f80e0cd095c, pid=48, tid=140189843019520
#
# JRE version: Java(TM) SE Runtime Environment (7.0_80-b15) (build 1.7.0_80-b15)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.80-b11 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V [libjvm.so+0x65395c] jni_SetByteArrayRegion+0x19c
#
# Core dump written. Default location: /apps/gateway/project/bin/core or core.48
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
错误信息记录
前两行主要描述了信号类型、发起信号的程序计数器、进程ID和线程ID,如下所示:
# SIGSEGV (0xb) at pc=0x00007f80e0cd095c, pid=48, tid=140189843019520
| | | | |
| | | | +--- 线程ID
| | | +----------- 进程ID
| | +-------------------------------- 程序计数器对应的指针
| +-------------------------------------------- 信号值(十六进制)
+--------------------------------------------------- 信号名称
信号名称是操作系统自身的一种信息,CentOS 7下共有以下35种,可在/usr/include/bits/signum.h中查看其具体的声明
信号名称 | 信号值 | 含义 |
---|---|---|
SIGHUP | 1 | Hangup (POSIX). |
SIGINT | 2 | Interrupt (ANSI). |
SIGQUIT | 3 | Quit (POSIX). |
SIGILL | 4 | Illegal instruction (ANSI). |
SIGTRAP | 5 | Trace trap (POSIX). |
SIGABRT | 6 | Abort (ANSI). |
SIGIOT | 6 | IOT trap (4.2 BSD). |
SIGBUS | 7 | BUS error (4.2 BSD). |
SIGFPE | 8 | Floating-point exception (ANSI). |
SIGKILL | 9 | Kill, unblockable (POSIX). |
SIGUSR1 | 10 | User-defined signal 1 (POSIX). |
SIGSEGV | 11 | Segmentation violation (ANSI). |
SIGUSR2 | 12 | User-defined signal 2 (POSIX). |
SIGPIPE | 13 | Broken pipe (POSIX). |
SIGALRM | 14 | Alarm clock (POSIX). |
SIGTERM | 15 | Termination (ANSI). |
SIGSTKFLT | 16 | Stack fault. |
SIGCLD | SIGCHLD | Same as SIGCHLD (System V). |
SIGCHLD | 17 | Child status has changed (POSIX). |
SIGCONT | 18 | Continue (POSIX). |
SIGSTOP | 19 | Stop, unblockable (POSIX). |
SIGTSTP | 20 | Keyboard stop (POSIX). |
SIGTTIN | 21 | Background read from tty (POSIX). |
SIGTTOU | 22 | Background write to tty (POSIX). |
SIGURG | 23 | Urgent condition on socket (4.2 BSD). |
SIGXCPU | 24 | CPU limit exceeded (4.2 BSD). |
SIGXFSZ | 25 | File size limit exceeded (4.2 BSD). |
SIGVTALRM | 26 | Virtual alarm clock (4.2 BSD). |
SIGPROF | 27 | Profiling alarm clock (4.2 BSD). |
SIGWINCH | 28 | Window size change (4.3 BSD, Sun). |
SIGPOLL | SIGIO | Pollable event occurred (System V). |
SIGIO | 29 | I/O now possible (4.2 BSD). |
SIGPWR | 30 | Power failure restart (System V). |
SIGSYS | 31 | Bad system call. |
SIGUNUSED | 31 | - |
JVM运行信息
接下来两行描述了JVM相关版本信息及运行配置信息,内容如下:
# JRE version: Java(TM) SE Runtime Environment (7.0_80-b15) (build 1.7.0_80-b15)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.80-b11 mixed mode linux-amd64 compressed oops)
上述文件内容可以得知以下几点:
- JRE版本号为1.7u80
- JVM版本号为24.80-b11
- JVM运行在Server模式下。对应的是Client模式,Client JVM适合需要快速启动和较小内存空间的应用,它适合交互性的应用,比如GUI;而Server JVM则是看重执行效率的应用的最佳选择,更适合服务端应用。
- JVM运行在混合模式下,即mixed mode,是JVM默认的运行模式。其他模式还有解释模式(interpreted mode)和编译模式(compiled mode),解释模式会强制JVM以解释方式执行所有的字节码,编译模式下JVM在第一次使用时会把所有的字节码编译成本地代码,这两种模式各有优劣,单独使用时都会有部分性能上的损失,所以默认使用混合模式即可,混合模式下对于字节码中多次被调用的部分,JVM会将其编译成本地代码以提高执行效率;而被调用很少(甚至只有一次)的方法在解释模式下会继续执行,从而减少编译和优化成本。
崩溃原因
接下来两行描述了引发崩溃问题的函数帧
# Problematic frame:
# V [libjvm.so+0x65395c] jni_SetByteArrayRegion+0x19c
| |
| +-- 类似于程序计数器, 以库名和偏移量表示。
| 对于与位置无关的库(JVM和其他库),可以不通过
| 调试器或通过反汇编程序转存偏移量周围结
|