Linux上Java进程运行数小时后偶尔崩溃的根因排查方法咨询
Linux上Java进程运行数小时后偶尔崩溃的根因排查方法咨询
老哥,遇到这种接手的老项目随机崩溃的情况确实闹心,先把你的问题背景理清楚:
- 我在Linux上启动的Java进程偶尔会崩溃
- 这是一个庞大的遗留Java项目(不是我们自己开发的)
- 我们能拿到项目源代码
- 进程运行期间可以用Jconsole监控
- 进程经常(但并非每次)在运行几小时后崩溃,而完整执行需要好几天
针对这个问题,我给你梳理几个实用的排查方向,一步步来定位根因:
先从系统层面排查(最容易忽略但关键)
- 检查系统OOM Killer日志:Linux内存不足时会触发OOM Killer主动杀掉占用内存高的进程,你可以去
/var/log/messages或者执行dmesg命令,搜索你的Java进程ID或者java关键词,看看有没有类似Out of memory: Killed process <pid> (java)的日志。如果有,那就是内存不足导致的。 - 查看进程退出码:进程崩溃后立刻执行
echo $?,如果返回码是137,基本可以确定是被SIGKILL信号干掉的,大概率就是OOM的问题。 - 启用堆转储:启动Java进程时加上参数
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/your/save/path,如果是内存溢出导致崩溃,会自动生成堆转储文件,之后用Memory Analyzer Tool(MAT)或者JProfiler分析哪里存在内存泄漏。
再看Java应用自身的日志和运行状态
- 重定向应用输出:启动进程时把标准输出和错误输出都重定向到日志文件,比如
java -jar your-app.jar > app-run.log 2>&1,这样崩溃前的所有异常堆栈、日志都会被记录下来,很多时候未捕获的异常会直接打在stderr里,之前可能没留意到。 - 启用GC日志:加上
-Xloggc:/path/to/gc.log -verbose:gc参数生成垃圾回收日志,分析崩溃前的GC情况——比如是不是Full GC频繁发生、内存占用持续上涨不回落,这都是内存泄漏的典型特征。 - 利用Jconsole深挖监控数据:监控的时候别只看表面,留意这几个点:
- 堆内存、非堆内存的变化趋势,是不是一直增长直到耗尽
- 线程数有没有持续增加,有没有死锁线程(Jconsole里有死锁检测功能)
- CPU使用率是不是突然飙升或者长时间维持高位
结合源代码排查潜在问题
- 排查主动退出逻辑:全局搜索源代码里的
System.exit()或者Runtime.getRuntime().exit(),看看有没有某些业务条件触发了主动退出,这种情况在遗留项目里并不少见。 - 检查未捕获异常处理:看看有没有自定义的
UncaughtExceptionHandler,有些处理逻辑可能在捕获到致命异常后直接退出进程;如果没有自定义处理器,默认会把异常堆栈打出来,这也是为啥重定向输出很重要。 - 排查异步/定时任务:因为是运行几小时后崩溃,大概率和定时任务、异步线程有关——比如某个任务循环执行时没释放资源(数据库连接、文件句柄),导致内存泄漏或者资源耗尽。可以用
lsof -p <进程ID>查看进程打开的文件句柄数,看看是不是持续上涨。
最后检查系统资源限制
- 看看Linux的文件句柄限制:执行
ulimit -a,如果open files数值很小(比如默认的1024),Java进程打开太多文件(比如数据库连接池、文件流没关闭)会触发报错甚至崩溃,可以临时调整为ulimit -n 65535,或者在系统配置里永久修改。 - 检查磁盘空间:堆转储文件、日志文件都需要磁盘空间,用
df -h看看是不是磁盘满了导致进程崩溃。
备注:内容来源于stack exchange,提问作者Santosh Tiwari
相关产品推荐
相关产品推荐

