文章插图
/data/tools/clean里调用了若干脚本,在每个脚本里用打出当前脚本名和进程号到crontab.pid里 。并和systemtap抓到的进程号62118对比,找到了KILL信号是从kill_non_run_App.sh脚本里发出 。
文章插图
调用System的exit如果在Java程序里显式调用System.exit结束进程,可以用arthas排查 。首先写脚本system_exit.as如下 。
options unsafe truestack java.lang.System exit -n 1运行命令nohup ./as.sh -f system_exit.as 69001 -b > system_exit.out 2>&1 &,即可监控进程69001调用的所有System.exit 。
Java调用的C++发生Crash此处发生的Crash案例和下文Java内Crash产生的原因一样,但现象不一样,大部分情况下,是Crash在C++代码,只产生core文件,不产生Java内Crash的Crash log;少量情况下Crash在JVM里,产生Java内Crash的Crash log 。如果Java通过JNI调用C++代码,在C++里发生Crash,JVM有时不会产生任何信息就退出,此时借助操作系统产生的core file分析进程退出原因,但操作系统默认关闭该功能,如下图所示core file size为0表示关闭该功能 。
文章插图
因此需要在进程的启动脚本里(只影响当前进程)设置ulimit -c ulimited来设置core file的大小,启动进程后,打开/proc/{pid}/limits,查看Max core file size的大小确认是否开启 。
文章插图
当发生Crash时,会生成core.pid文件,一般core.pid文件会非常大,因为该文件包含了所有虚拟内存大小,所以大于物理内存,如下图所示core.44729共53GB 。
文章插图
接下来使用命令gdb bin/java core.44729打开core文件,发现是rocksdb start thread时挂的,挂在libstdc++里,这是glibc库,基本不可能出问题,因此该堆栈可能是表象,有其他原因导致start thread失败 。
文章插图
注意到打开core文件时,有太多线程-LWP轻量级进程 。
文章插图
然后在gdb里用info threads,发现有三万多个线程,都在wait锁状态,基本确认三万多个线程,导致内存太大,创建不出来新的线程,因此挂在start thread里 。
文章插图
接着分析三万多个线程都是什么线程,随机选几十个线程,打出每个线程的堆栈,可以看到大部分线程都是jvm线程 。因为rocksdb创建出来的线程是:
从/tmp/librocksdbjni8646115773822033422.so来的;而jvm创建出来的线程都是从/usr/java/jdk1.8.0_191-amd64/jre/lib/amd64/server/libjvm.so来的,这部分线程占了大部分 。
文章插图
文章插图
因此问题出在Java代码里,产生core.pid文件的进程,虽然没有产生crash log,但也是因为Java 线程太多,导致C++代码创建线程时挂掉 。至于为什么Java线程太多请看Java内Crash 。
另外,core.pid完整的保留了C++组件Crash时的现场,包括变量、寄存器的值等,如果真的因为C++组件有Bug而Crash,例如空指针等 。首先自行找到C++源码,找出怀疑空指针的变量{variableName},通过在gdb里执行命令:p {variableName},可以看出每个变量的值,从而找出空指针的变量 。
Java内Crash排查Java内Crash的原因如OOM等,需要配置JVM的如下参数:
-XX:ErrorFile
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath 。
JVM内发生Crash时,会在-XX:ErrorFile配置的路径下生成crash log 。而-XX:+HeapDumpOnOutOfMemoryError、-XX:HeapDumpPath用于发生OOM时生成Dump堆,用于还原现场 。下图所示为产生的crash log 。可以看到创建线程时发生OutOfMemory导致进程挂掉 。
文章插图
从下图crash log可以看到有两万四千个Datanode State machine Thread线程都在等锁 。到此确认上文Java调用C++发生Crash 产生core.pid的进程和产生crash log的进程都是因为两万多个Datanode State Machine Thread挂掉 。
推荐阅读
- javascript 知识普及之 FormData
- 技术转载 || 使用java API进行zip递归压缩文件夹以及解压
- 两万字长文读懂 Java 集合
- 腾讯算法:判断一个数是否在40亿个整数中?最后附java代码
- Java最全面试题之Spring篇
- 什么是Java可变参数列表?怎么和重载机制配合使用?
- Java安全编码之sql注入
- 异步文件通道Java NIO你需要了解多少,来看看这篇文章
- Java开源框架之SpringMVC原理及源码解析
- 破解 Java Agent 探针黑科技