首页 > 解决方案 > 使用 gcore 生成的 java corefile 有用吗?

问题描述

我们有一个JAVA应用程序通过消耗一些(未知?)资源来使我们的redhat服务器(30 核 / 512Go ram)崩溃,从而阻止其他组件创建新线程,我们目前正在通过终止向线程发送垃圾邮件的进程来解决这个问题每次出现问题时,大约每 15 天出现一次,我们尝试在/etc/security/limits.conf上设置巨大的值,但在达到该限制之前我们就遇到了问题。

我上次使用ps -efL |计算了线程数。wc -l,对于我们的野兽来说,知道当时 CPU/RAM 消耗很低,10000个线程是不是很多?我使用gstack试图找出它卡在哪里但是因为它是一个 JAVA 程序 idk 如果输出有意义?但我可以在那里识别出一个模式:9000 个线程中的大多数看起来像这样:

Thread 9049 (Thread 0x7f43d5087700 (LWP 123925)):
#0  0x00007f43d791e705 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x00007f43d6a94f33 in os::PlatformEvent::park() () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#2  0x00007f43d6a58e67 in Monitor::IWait(Thread*, long) () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#3  0x00007f43d6a59786 in Monitor::wait(bool, long, bool) () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#4  0x00007f43d6c48e1b in GangWorker::loop() () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#5  0x00007f43d6a9bd48 in java_start(Thread*) () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#6  0x00007f43d791adf5 in start_thread () from /lib64/libpthread.so.0
#7  0x00007f43d722f1ad in clone () from /lib64/libc.so.6
Thread 9048 (Thread 0x7f43d4f86700 (LWP 123926)):
#0  0x00007f43d791e705 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x00007f43d6a94f33 in os::PlatformEvent::park() () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#2  0x00007f43d6a58e67 in Monitor::IWait(Thread*, long) () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#3  0x00007f43d6a59786 in Monitor::wait(bool, long, bool) () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#4  0x00007f43d6c48e1b in GangWorker::loop() () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#5  0x00007f43d6a9bd48 in java_start(Thread*) () from /opt/3pp/jdk1.8.0_25/jre/lib/amd64/server/libjvm.so
#6  0x00007f43d791adf5 in start_thread () from /lib64/libpthread.so.0
#7  0x00007f43d722f1ad in clone () from /lib64/libc.so.6

同样在杀死我使用gcore -o /tmp/dump.txt的进程之前,它是获取java进程核心文件的正确方法吗?

当我尝试使用gdb查看时,我没有得到调试符号,也没有核心转储,这是检查此类文件的正确方法吗?

M1:~# gdb /opt/3pp/jre/bin/java /tmp/dump.txt.123913 
GNU gdb (GDB) 
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /opt/3pp/jre/bin/java...(no debugging symbols 
"/tmp/dump.txt.123913" is not a core dump: File format not recognized
Missing separate debuginfos, use: debuginfo-install jre1.8.0_25-1.8.0_25-fcs.x86_64

在此先感谢您的时间。

标签: javalinuxjvmgdbgcore

解决方案


我上次使用 ps -efL | 计算了线程数。wc -l ,对于我们的野兽来说,知道当时 CPU/RAM 消耗很低,10000 个线程是不是很多?

这不是一个微不足道的线程数,但不,10K 线程并不是那么多,尤其是对于 30 核机器。我目前使用的 4 核 Windows 桌面大约有 3K。

我使用 gstack 试图找出它卡在哪里但是因为它是一个 JAVA 程序 idk 如果输出有意义?

我从未尝试过使用本机线程堆栈调试 Java,但对我来说,堆栈跟踪看起来像是一个“停放”的线程。换句话说,某个线程池中的一个线程没有任何事情可做,所以它正在等待工作。有关更多详细信息,请参阅答案。

同样在杀死我使用 gcore -o /tmp/dump.txt 的进程之前,它是获取java进程核心文件的正确方法吗?

它可能有一些价值,但我建议使用特定于 java 的工具来完成这项工作。首先想到的是jcmdJDK附带的。这是一个帮助您入门的链接。Java 9 的版本有一些更好的文档,并且非常相似。

我具体要做的是使用Thread.print命令jcmd来打印 java 级别的堆栈跟踪并将GC.heap_dump整个 java 堆转储到一个.hprof文件中,该文件以后可以通过MAT等工具进行分析。

如果您使用具有“商业功能”的 JDK 8 ,您还可以启用JFR(跟踪流程执行的 Java Flight Recorder。JFR 创建的文件可以使用Oracle 的“任务控制”或替代“任务控制”,例如来自 Azul 的称为 Zulu的。

最后,您还可以尝试使用jconsole连接到进程,这是 JDK 附带的另一个工具。

祝你好运。


推荐阅读