jps 未列出 tomcat 进程并且 jmap 无法创建堆转储

问题描述

我正在运行 tomcat (9.0.39.0) 服务器,由用户 cpappt 启动并使用 pid 运行:1682650。运行此服务器的机器不是裸机但是 VMware 机器和 JVM 来自 OpenJ9

> ps -ef | grep Bootstrap
cpappt   1682650       1  0 Jan01 ?        01:09:58 /srv/jdk11/bin/java
  -Djava.util.logging.config.file=/srv/test/cpappt/tomcat/conf/logging.properties
  -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -server 
  -xms32m -Xmx2048m -XX:+HeapDumpOnOutOfMemoryError
  -Dcrewportalenvironment=test
  -Denvironment=test
  -Doracle.net.tns_admin=/CONfig/global/ORA/HA
  -Dspring.profiles.active=test,notification-services-intern
  -Djdk.tls.ephemeralDHKeySize=2048
  -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
  -Dorg.apache.catalina.security.SecurityListener.UMASK=0022
  -Djava.awt.headless=true
  -Dcom.sun.management.jmxremote
  -Dfile.encoding=UTF-8
  -Dsun.jnu.encoding=UTF-8
  -Dcom.sun.management.jmxremote.port=7305
  -Dcom.sun.management.jmxremote.ssl=false
  -Dcom.sun.management.jmxremote.password.file=conf/jmxremote.password
  -Dignore.endorsed.dirs= -classpath /srv/test/cpappt/tomcat/bin/bootstrap.jar:/srv/test/cpappt/tomcat/bin/tomcat-juli.jar
  -Dcatalina.base=/srv/test/cpappt/tomcat
  -Dcatalina.home=/srv/test/cpappt/tomcat
  -Djava.io.tmpdir=/srv/test/cpappt/tomcat/temp org.apache.catalina.startup.Bootstrap start

我想提取 tomcat 的 heap dump 来分析潜在的内存泄漏。

我尝试使用jps获取tomcat服务器的pid,可惜我只看到了pid本身的jps

> jps -l
952152 jdk.jcmd/openj9.tools.attach.diagnostics.tools.Jps

而且我还以启动 tomcat 服务器的同一用户身份运行 jps 命令

> whoami 
cpappt

我也试过运行jps命令,添加tomcat启动脚本中指定的java.io.tmpdir,结果和之前一样(备注:tmpdir本身是空的)。

jps -l -J-Djava.io.tmpdir=/srv/test/cpappt/tomcat/temp

(补充说明:如果我启动了一个小的“Foo 程序”,jps 会向我展示这个程序的 pid。)

然后我尝试使用 pid 命令中的 ps 创建一个 堆转储,但失败了:

> jmap -dump:live,format=b,file=/tmp/dump.hprof 1682650
unrecognized option -dump:live,file=/tmp/dump.hprof
jmap: obtain heap information about a Java process
 Usage:
    jmap <option>* <vmid>
        <vmid>: Attach API VM ID as shown in jps or other Attach API-based tools
        <vmid>s are read from stdin if none are supplied as arguments
    -histo: print statistics about classes on the heap,including number of objects and aggregate size
    -histo:live : Print only live objects
    -J: supply arguments to the Java VM running jmap
NOTE: this utility might significantly affect the performance of the target VM.
At least one option must be selected.

如果我只是尝试查看直方图,这也会失败:

> jmap -histo:live 1682650
Error getting data from 1682650: Exception connecting to 1682650

还有 jcmd 无法创建转储:

> jcmd 1682650 GC.heap_dump /tmp/heapdump
Error getting data from 1682650: Exception connecting to 1682650
...

我以某种方式怀疑这两个问题(jpsjmap)是相关的... 所以,如果有人知道可能是什么问题,或者我知道如何创建堆转储,那就太好了。

来自 tomcat 服务器(和 java)的附加信息:

Server version number: 9.0.39.0
OS Name:               Linux
OS Version:            5.7.0-0.bpo.2-amd64
Architektur:           amd64
Java Home:             /srv/jdk-11.0.8+10_openj9
JVM Version:           11.0.8+10
JVM Hersteller:        Eclipse OpenJ9

> java -version
openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.8+10)
Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.21.0,JRE 11 Linux amd64-64-Bit Compressed References 20200715_697 (JIT enabled,AOT enabled)
OpenJ9   - 34cf4c075
omr      - 113e54219
JCL      - 95bb504fbb based on jdk-11.0.8+10)

> which java
/srv/jdk11/bin/java

> which jps
/srv/jdk11/bin/java

> which jmap 
/srv/jdk11/bin/jmap

更新:2021-01-09

我终于找到了知道 jmx 用户密码的同事,所以使用 jconsole 我能够触发 heap dump,但我只能调用 triggerClassicHeapDump()。 我将文件复制到本地机器上,并想用 Eclipse MemoryAnalyzer 对其进行分析(我还添加Diagnostic Tool Framework for Java (DTFJ))。

但是当我尝试打开文件时,我现在收到一条错误消息...

Error opening heap dump 'heapdump.20210119.100934.2621412.0001.txt'. Check the error log for further details.
Error opening heap dump 'heapdump.20210119.100934.2621412.0001.txt'. Check the error log for further details.
Error opening heap dump 'heapdump.20210119.100934.2621412.0001.txt'
Unable to read dump .../heapdump.20210119.100934.2621412.0001.phd Metafile .../heapdump.20210119.100934.2621412.0001.txt in DTFJ format DTFJ-PHD (java.io.IOException)
Unable to read dump .../heapdump.20210119.100934.2621412.0001.phd Metafile .../heapdump.20210119.100934.2621412.0001.txt in DTFJ format DTFJ-PHD
Error parsing Javacore (java.io.IOException)
Error parsing Javacore
com.ibm.dtfj.javacore.parser.framework.scanner.ScannerException: Maximum line length (32768) exceeded. Input file corrupt or not a javacore. (com.ibm.dtfj.javacore.parser.framework.parser.ParserException)
com.ibm.dtfj.javacore.parser.framework.scanner.ScannerException: Maximum line length (32768) exceeded. Input file corrupt or not a javacore.
Maximum line length (32768) exceeded. Input file corrupt or not a javacore. (com.ibm.dtfj.javacore.parser.framework.scanner.ScannerException)
Maximum line length (32768) exceeded. Input file corrupt or not a javacore.
Unable to read dump .../heapdump.20210119.100934.2621412.0001.txt Metafile null in DTFJ format DTFJ-Javacore (java.io.IOException)
Unable to read dump .../heapdump.20210119.100934.2621412.0001.txt Metafile null in DTFJ format DTFJ-Javacore
Error parsing Javacore (java.io.IOException)
Error parsing Javacore
com.ibm.dtfj.javacore.parser.framework.scanner.ScannerException: Maximum line length (32768) exceeded. Input file corrupt or not a javacore. (com.ibm.dtfj.javacore.parser.framework.parser.ParserException)
com.ibm.dtfj.javacore.parser.framework.scanner.ScannerException: Maximum line length (32768) exceeded. Input file corrupt or not a javacore.
Maximum line length (32768) exceeded. Input file corrupt or not a javacore. (com.ibm.dtfj.javacore.parser.framework.scanner.ScannerException)
Maximum line length (32768) exceeded. Input file corrupt or not a javacore.

解决方法

我已经在 tomcat 的启动脚本中添加了 -Xdump:heap:events=user(参见 Xdump Option Builder)并重新启动了服务器。

> ps -ef | grep Bootstrap
cpappt   1919301       1 99 14:38 pts/0    00:01:00 /srv/jdk11/bin/java 
 -Xms32m -Xmx2048m -XX:+HeapDumpOnOutOfMemoryError
 -Xdump:heap:events=user
 ...

现在我可以使用 kill -3 <pid> 创建堆转储(查看 superuser: what-does-kill-3-mean)。 在 catalina.base 目录中创建了两个文件:

  • javacore.<XXX>.txt(原始线程转储 (-3 := SIGQUIT))和
  • heapdump.<YYY>.phd(好吧,实际的堆转储)

最后我可以用 heapdump.<YYY>.phd

打开 Eclipse MAT 文件

附加说明:我们将 openj9 版本更新为当前版本 (23.0)。

> java -version 
openjdk version "11.0.9" 2020-10-20
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.9+11)
Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.23.0,JRE 11 Linux amd64-64-Bit Compressed References 20201022_810 (JIT enabled,AOT enabled)

现在 jps 也确实找到了 tomcat 服务器

> jps -l
1919301 org.apache.catalina.startup.Bootstrap
1921897 jdk.jcmd/openj9.tools.attach.diagnostics.tools.Jps

还有 jcmd 有效:

> jcmd 1919301 Dump.heap dump
Dump written to .../tomcat/dump
,

还可以考虑使用 -Xdump:system:events=user 因为生成的核心文件包含更多信息 - 但是 IBM DTFJ 读取 OpenJ9 生成的核心文件存在问题。

内存分析器还可以生成堆转储 - 请参阅文件 > 获取堆转储,但“附加 API”和“使用 Helper JVM 附加 API”可能需要一些配置。 Memory Analyzer 1.12 在获取堆转储方面有一些改进,所以请尝试最新版本。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...