JVM致命错误日志(hs_err_pid.log)分析

简介: JVM致命错误日志(hs_err_pid.log)分析 发表于5天前(2015-08-28 17:10)   当jvm出现致命错误时,会生成一个错误文件 hs_err_pid.log,其中包括了导致jvm crash的重要信息,可以通过分析该文件定位到导致crash的根源,从而改善以保证系统稳定。

JVM致命错误日志(hs_err_pid.log)分析

发表于5天前(2015-08-28 17:10)  


当jvm出现致命错误时,会生成一个错误文件 hs_err_pid<pid>.log,其中包括了导致jvm crash的重要信息,可以通过分析该文件定位到导致crash的根源,从而改善以保证系统稳定。当出现crash时,该文件默认会生成到工作目录下,然而可以通过jvm参数指定生成路径(JDK6中引入):

?
1
-XX:ErrorFile=./hs_err_pid<pid>.log

该文件包含如下几类关键信息:

  • 日志头文件

  • 导致crash的线程信息

  • 所有线程信息

  • 安全点和锁信息

  • 堆信息

  • 本地代码缓存

  • 编译事件

  • gc相关记录

  • jvm内存映射

  • jvm启动参数

  • 服务器信息

下面用一个crash demo文件逐步解读这些信息,以便大家以后碰到crash时方便分析。

日志头文件

日志头文件包含概要信息,简述了导致crash的原因。而导致crash的原因很多,常见的原因有jvm自身的bug,应用程序错误,jvm参数配置不当,服务器资源不足,jni调用错误等。

现在参考下如下描述:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV ( 0xb ) at pc= 0x00007fb8b18fdc6c , pid= 191899 , tid= 140417770411776
#
# JRE version: Java(TM) SE Runtime Environment ( 7 .0_55-b13) (build  1.7 .0_55-b13)
# Java VM: Java HotSpot(TM)  64 -Bit Server VM ( 24.55 -b03 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# J  org.apache.http.impl.cookie.BestMatchSpec.formatCookies(Ljava/util/List;)Ljava/util/List;
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping,  try  "ulimit -c unlimited"  before starting Java again
#
# If you would like to submit a bug report, please visit:
#   http: //bugreport.sun.com/bugreport/crash.jsp
#

这里一个重要信息是“SIGSEGV(0xb)”表示jvm crash时正在执行jni代码,而不是在执行java或者jvm的代码,如果没有在应用程序里手动调用jni代码,那么很可能是JIT动态编译时导致的该错误。其中SIGSEGV是信号名称,0xb是信号码,pc=0x00007fb8b18fdc6c指的是程序计数器的值,pid=191899是进程号,tid=140417770411776是线程号。

PS:除了“SIGSEGV(0xb)”以外,常见的描述还有“EXCEPTION_ACCESS_VIOLATION”,该描述表示jvm crash时正在执行jvm自身的代码,这往往是因为jvm的bug导致的crash;另一种常见的描述是“EXCEPTION_STACK_OVERFLOW”,该描述表示这是个栈溢出导致的错误,这往往是应用程序中存在深层递归导致的。

还有一个重要信息是:

# Problematic frame:

# J org.apache.http.impl.cookie.BestMatchSpec.formatCookies(Ljava/util/List;)Ljava/util/List;

这表示出现crash时jvm正在执行的代码,这里的“J”表示正在执行java代码,后面的表示执行的方法栈。除了“J”外,还有可能是“C”、“j”、“V”、“v”,它们分别表示:

  • C: Native C frame

  • j: Interpreted Java frame

  • V: VMframe

  • v: VMgenerated stub frame

  • J: Other frame types, including compiled Java frames

加上前面对SIGSEGV(0xb)”的分析,现在可以断定是JIT动态编译导致的该错误。

查阅资料发现:

此异常是由于jdk JIT compiler optimization 导致,bug id 8021898,官网描述如下:

?
1
The JIT compiler optimization leads to a SIGSEGV or an NullPointerException at a place it must not happen.

jdk1.7.0_25到1.7.0_55这几个版本都存在此bug,1.7.0_60后修复。可通过升级jdk解决此异常,可参考 http://bugs.java.com/view_bug.do?bug_id=8021898

到这里该问题已经分析出原因了,但是咱们可以再深入一步,分析下其它信息。

导致crash的线程信息

文件下面是导致crash的线程信息和该线程栈信息,描述信息如下:

?
1
2
3
Current thread ( 0x00007fb7b4014800 ):  JavaThread  "catalina-exec-251"  daemon [_thread_in_Java, id= 205044 , stack( 0x00007fb58f435000 , 0x00007fb58f536000 )]
 
siginfo:si_signo=SIGSEGV: si_errno= 0 , si_code= 1  (SEGV_MAPERR), si_addr= 0x0000003f96dc9c6c

以上表示导致出错的线程是0x00007fb7b4014800(指针),线程类型是JavaThread,JavaThread表示执行的是java线程,关于该线程其它类型还可能是:

  • VMThread:jvm的内部线程

  • CompilerThread:用来调用JITing,实时编译装卸class 。 通常,jvm会启动多个线程来处理这部分工作,线程名称后面的数字也会累加,例如:CompilerThread1

  • GCTaskThread:执行gc的线程

  • WatcherThread:jvm周期性任务调度的线程,是一个单例对象。 该线程在JVM内使用得比较频繁,比如:定期的内存监控、JVM运行状况监控,还有我们经常需要去执行一些jstat 这类命令查看gc的情况

  • ConcurrentMarkSweepThread:jvm在进行CMS GC的时候,会创建一个该线程去进行GC,该线程被创建的同时会创建一个SurrogateLockerThread(简称SLT)线程并且启动它,SLT启动之后,处于等待阶段。CMST开始GC时,会发一个消息给SLT让它去获取Java层Reference对象的全局锁:Lock

后面的"catalina-exec-251"表示线程名,带有catalina前缀的线程一般是tomcat启动的线程,“daemon”表示该线程为守护线程,再后面的“[_thread_in_Java”表示线程正在执行解释或者编译后的Java代码,关于该描述其它类型还可能是:

  • _thread_in_native:线程当前状态

  • _thread_uninitialized:线程还没有创建,它只在内存原因崩溃的时候才出现

  • _thread_new:线程已经被创建,但是还没有启动

  • _thread_in_native:线程正在执行本地代码,一般这种情况很可能是本地代码有问题

  • _thread_in_vm:线程正在执行虚拟机代码

  • _thread_in_Java:线程正在执行解释或者编译后的Java代码

  • _thread_blocked:线程处于阻塞状态

  • …_trans:以_trans结尾,线程正处于要切换到其它状态的中间状态

最后的“id=205044”表示线程ID,stack(0x00007fb58f435000,0x00007fb58f536000)表示栈区间。

“siginfo:si_signo=SIGSEGV: si_errno=0, si_code=1 (SEGV_MAPERR), si_addr=0x0000003f96dc9c6c”这部分是导致虚拟机终止的非预期的信号信息:其中si_errno和si_code是Linux下用来鉴别异常的,Windows下是一个ExceptionCode。

所有线程信息

再下面是线程信息:

?
1
2
3
4
5
6
7
8
Java Threads: ( => current thread )
   0x00007fb798015800  JavaThread  "catalina-exec-280"  daemon [_thread_blocked, id= 206093 , stack( 0x00007fb58d718000 , 0x00007fb58d819000 )]
   0x00007fb7a4016800  JavaThread  "catalina-exec-279"  daemon [_thread_blocked, id= 206091 , stack( 0x00007fb58d819000 , 0x00007fb58d91a000 )]
   ... ...(省略)
   
   Other Threads:
   0x00007fb8b4231000  VMThread [stack:  0x00007fb854eb6000 , 0x00007fb854fb7000 ] [id= 192015 ]
   0x00007fb8b4321000  WatcherThread [stack:  0x00007fb835e6c000 , 0x00007fb835f6d000 ] [id= 192414 ]

信息和上面介绍的类似,其中[_thread_blocked表示线程阻塞。

安全点和锁信息

再下面是安全点和锁信息:

?
1
2
3
VM state:not at safepoint (normal execution)
 
VM Mutex/Monitor currently owned by a thread: None

安全线信息为正常运行,其它可能得描述还有:

  • not at a safepoint:正常运行状态

  • at safepoint:所有线程都因为虚拟机等待状态而阻塞,等待一个虚拟机操作完成

  • synchronizing:一个特殊的虚拟机操作,要求虚拟机内的其它线程保持等待状态

锁信息为未被线程持有,Mutex是虚拟机内部的锁,而Monitor则是synchronized锁或者其它关联到的Java对象。

堆信息

再下面是堆信息:

?
1
2
3
4
5
6
7
8
9
Heap
  par  new  generation   total 2293760K, used 1537284K [ 0x00000006f0000000 0x0000000790000000 0x0000000790000000 )
   eden space 1966080K,   78 % used [ 0x00000006f0000000 0x000000074dc97aa8 0x0000000768000000 )
   from space 327680K,    0 % used [ 0x0000000768000000 0x00000007680a9580 0x000000077c000000 )
   to   space 327680K,    0 % used [ 0x000000077c000000 0x000000077c000000 0x0000000790000000 )
  concurrent mark-sweep generation total 1572864K, used 49449K [ 0x0000000790000000 0x00000007f0000000 0x00000007f0000000 )
  concurrent-mark-sweep perm gen total 262144K, used 49857K [ 0x00000007f0000000 0x0000000800000000 0x0000000800000000 )
  
  Card table byte_map: [ 0x00007fb8b8fa8000 , 0x00007fb8b9829000 ] byte_map_base:  0x00007fb8b5828000

堆信息包括:新生代、老生代、永久代信息。这里标识了使用CMS垃圾收集器。

下面的“Card table”表示一种卡表,是jvm维护的一种数据结构,用于记录更改对象时的引用,以便gc时遍历更少的table和root。

本地代码缓存

再下面是本地代码缓存信息:

?
1
2
Code Cache  [ 0x00007fb8b1000000 0x00007fb8b1a60000 0x00007fb8b4000000 )
  total_blobs= 3580  nmethods= 3111  adapters= 421  free_code_cache=38857Kb largest_free_block= 39469312

这是一块用于编译和保存本地代码的内存;注意是本地代码,它和PermGen(永久代)是不一样的,永久是用来存放jvm和java类的元数据的。

编译事件

再下面是本地代码编译信息:

?
1
2
3
4
5
6
Compilation events ( 10  events):
Event:  110587.798  Thread  0x00007fb8b425a800  3338              java.util.HashSet::remove ( 20  bytes)
Event:  110587.804  Thread  0x00007fb8b425a800  nmethod  3338  0x00007fb8b168a9d0  code [ 0x00007fb8b168ab60 0x00007fb8b168afa8 ]
... ...(省略)
Event:  112147.387  Thread  0x00007fb8b425a800  3342              org.apache.http.impl.cookie.BestMatchSpec::formatCookies ( 116  bytes)
Event:  112147.465  Thread  0x00007fb8b425a800  nmethod  3342  0x00007fb8b18fcd50  code [ 0x00007fb8b18fd1a0 0x00007fb8b18ff338 ]

可以看到,一共编译了10次;其中包含org.apache.http.impl.cookie.BestMatchSpec::formatCookies的编译;这和前面的结论相吻合。

gc相关记录

再下面是gc执行记录:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GC Heap History ( 10  events):
Event:  110665.975  GC heap before
{Heap before GC invocations= 255  (full  31 ):
  par  new  generation   total 2293760K, used 1966777K [ 0x00000006f0000000 0x0000000790000000 0x0000000790000000 )
   eden space 1966080K,  100 % used [ 0x00000006f0000000 0x0000000768000000 0x0000000768000000 )
   from space 327680K,    0 % used [ 0x0000000768000000 0x00000007680ae480 0x000000077c000000 )
   to   space 327680K,    0 % used [ 0x000000077c000000 0x000000077c000000 0x0000000790000000 )
  concurrent mark-sweep generation total 1572864K, used 49237K [ 0x0000000790000000 0x00000007f0000000 0x00000007f0000000 )
  concurrent-mark-sweep perm gen total 262144K, used 49856K [ 0x00000007f0000000 0x0000000800000000 0x0000000800000000 )
Event:  110665.981  GC heap after
Heap after GC invocations= 256  (full  31 ):
  par  new  generation   total 2293760K, used 693K [ 0x00000006f0000000 0x0000000790000000 0x0000000790000000 )
   eden space 1966080K,    0 % used [ 0x00000006f0000000 0x00000006f0000000 0x0000000768000000 )
   from space 327680K,    0 % used [ 0x000000077c000000 0x000000077c0ad6f8 0x0000000790000000 )
   to   space 327680K,    0 % used [ 0x0000000768000000 0x0000000768000000 0x000000077c000000 )
  concurrent mark-sweep generation total 1572864K, used 49237K [ 0x0000000790000000 0x00000007f0000000 0x00000007f0000000 )
  concurrent-mark-sweep perm gen total 262144K, used 49856K [ 0x00000007f0000000 0x0000000800000000 0x0000000800000000 )
}
... ...(省略)

可以看到gc次数为10次(full gc),然后后面描述了每次gc前后的内存信息;看一看到并没有内存不足等问题。

jvm内存映射

再下面是jvm加载的库信息:

?
1
2
3
4
5
6
7
8
9
10
11
12
Dynamic libraries:
00400000 - 00401000  r-xp  00000000  08 : 02  39454583                            /home/service/jdk1. 7 .0_55/bin/java
00600000 - 00601000  rw-p  00000000  08 : 02  39454583                            /home/service/jdk1. 7 .0_55/bin/java
013cd000-013ee000 rw-p  00000000  00 : 00  0                                   [heap]
6f0000000- 800000000  rw-p  00000000  00 : 00  0 
3056400000 - 3056416000  r-xp  00000000  08 : 02  57409539                        /lib64/libgcc_s- 4.4 . 7 - 20120601 .so. 1
3056416000 - 3056615000  ---p  00016000  08 : 02  57409539                        /lib64/libgcc_s- 4.4 . 7 - 20120601 .so. 1
3056615000 - 3056616000  rw-p  00015000  08 : 02  57409539                        /lib64/libgcc_s- 4.4 . 7 - 20120601 .so. 1
353be00000-353be20000 r-xp  00000000  08 : 02  57409933                        /lib64/ld- 2.12 .so
353c01f000-353c020000 r--p 0001f000  08 : 02  57409933                        /lib64/ld- 2.12 .so
353c020000-353c021000 rw-p  00020000  08 : 02  57409933                        /lib64/ld- 2.12 .so
... ...(省略)

这些信息是虚拟机崩溃时的虚拟内存列表区域。它可以告诉你崩溃原因时哪些类库正在被使用,位置在哪里,还有堆栈和守护页信息。以列表中第一条为例介绍下:

  • 00400000-00401000:内存区域

  • r-xp:权限,r/w/x/p/s分别表示读/写/执行/私有/共享

  • 00000000:文件内的偏移量

  • 08:02:文件位置的majorID和minorID

  • 39454583:索引节点号

  • /home/service/jdk1.7.0_55/bin/java:文件位置

jvm启动参数

再下面是jvm启动参数信息:

?
1
2
3
4
5
6
7
8
9
VM Arguments:
jvm_args: -Djava.util.logging.config.file=/home/service/tomcat7007-account-web/conf/logging.properties -Xmx4096m -Xms4096m -Xmn2560m -XX:SurvivorRatio= 6  -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:/home/work/webdata/logs/tomcat7007-account-web/develop/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/work/webdata/logs/tomcat7007-account-web/develop/ -Dtomcatlogdir=/home/work/webdata/logs/tomcat7007-account-web/develop -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port= 7407  -Dcom.sun.management.jmxremote.authenticate= false  -Dcom.sun.management.jmxremote.ssl= false  -Djava.endorsed.dirs=/home/service/tomcat7007-account-web/endorsed -Dcatalina.base=/home/service/tomcat7007-account-web -Dcatalina.home=/home/service/tomcat7007-account-web -Djava.io.tmpdir=/home/service/tomcat7007-account-web/temp 
java_command: org.apache.catalina.startup.Bootstrap start
Launcher Type: SUN_STANDARD
 
Environment Variables:
JAVA_HOME=/home/service/jdk1. 7 .0_55
PATH=/opt/zabbix/bin:/opt/zabbix/sbin:/home/service/jdk1. 7 .0_55/bin:/home/work/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/work/bin
SHELL=/bin/bash

上面是jvm参数,下面是系统的环境配置。

服务器信息

再下面是服务器信息:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/proc/meminfo:
MemTotal:        65916492  kB
MemFree:         14593468  kB
Buffers:           222452  kB
Cached:          28502452  kB
SwapTotal:              0  kB
SwapFree:               0  kB
... ...(省略)
/proc/cpuinfo:
processor   :  0
vendor_id   : GenuineIntel
cpu family :  6
model       :  62
model name : Intel(R) Xeon(R) CPU E5- 2420  v2 @  2 .20GHz
stepping    :  4
... ...(省略)

上面是内存信息,主要关注下swap信息,看看有没有使用虚拟内存;下面是cpu信息。



转自    http://my.oschina.net/xionghui/blog/498785

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1天前
|
存储 监控 NoSQL
【MongoDB 专栏】MongoDB 的日志管理与分析
【5月更文挑战第11天】MongoDB日志管理与分析至关重要,包括系统日志和操作日志,用于监控、故障排查和性能优化。合理配置日志详细程度、存储位置和保留策略,使用日志分析工具提升效率,发现性能瓶颈和安全性问题。日志分析有助于优化查询、调整配置,确保数据安全,并可与其他监控系统集成。面对日志量增长的挑战,需采用新技术如分布式存储和数据压缩来保障存储和传输。随着技术发展,不断进化日志管理与分析能力,以支持MongoDB的稳定高效运行。
【MongoDB 专栏】MongoDB 的日志管理与分析
|
3天前
|
算法 Java
深入浅出JVM(十六)之三色标记法与并发可达性分析
深入浅出JVM(十六)之三色标记法与并发可达性分析
|
5天前
|
存储 Arthas 监控
JVM工作原理与实战(三十):堆内存状况的对比分析
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了堆内存状况的对比分析、产生内存溢出的原因等内容。
12 0
|
5天前
|
监控 算法 安全
JVM工作原理与实战(二十三):堆的垃圾回收-引用计数法和可达性分析法
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了判断堆上的对象是否可以回收的方法(引用计数法、可达性分析法)、查看垃圾回收日志等内容。
12 0
|
5天前
|
C++
JNI Log 日志输出
JNI Log 日志输出
14 1
|
5天前
|
存储 运维 大数据
聊聊日志硬扫描,阿里 Log Scan 的设计与实践
泛日志(Log/Trace/Metric)是大数据的重要组成,伴随着每一年业务峰值的新脉冲,日志数据量在快速增长。同时,业务数字化运营、软件可观测性等浪潮又在对日志的存储、计算提出更高的要求。
|
12天前
|
XML Java Maven
Springboot整合与使用log4j2日志框架【详解版】
该文介绍了如何在Spring Boot中切换默认的LogBack日志系统至Log4j2。首先,需要在Maven依赖中排除`spring-boot-starter-logging`并引入`spring-boot-starter-log4j2`。其次,创建`log4j2-spring.xml`配置文件放在`src/main/resources`下,配置包括控制台和文件的日志输出、日志格式和文件切分策略。此外,可通过在不同环境的`application.yml`中指定不同的log4j2配置文件。最后,文章提到通过示例代码解释了日志格式中的各种占位符含义。
|
12天前
|
运维 监控 Go
Golang深入浅出之-Go语言中的日志记录:log与logrus库
【4月更文挑战第27天】本文比较了Go语言中标准库`log`与第三方库`logrus`的日志功能。`log`简单但不支持日志级别配置和多样化格式,而`logrus`提供更丰富的功能,如日志级别控制、自定义格式和钩子。文章指出了使用`logrus`时可能遇到的问题,如全局logger滥用、日志级别设置不当和过度依赖字段,并给出了避免错误的建议,强调理解日志级别、合理利用结构化日志、模块化日志管理和定期审查日志配置的重要性。通过这些实践,开发者能提高应用监控和故障排查能力。
87 1
|
12天前
|
存储 监控 关系型数据库
PHP编写的电脑监控软件:用户登录日志记录与分析
使用PHP编写简单但功能强大的电脑监控软件,记录用户登录日志并进行分析。代码示例展示了如何获取并存储用户IP地址和登录时间到数据库,然后进行登录数据的分析,如计算登录频率和常见登录时间。此外,还介绍了如何通过定时任务自动将监控数据提交到网站,以便实时监控用户活动,提升系统安全性和稳定性。
38 0
|
13天前
|
弹性计算 运维 Shell