Jmap无法连接进行转储
我们有一个应用程序的公开testing版,偶尔会导致heappace溢出。 JVM通过永久休假来作出反应。
为了分析这个,我想在失败的地方偷看一下记忆。 Java不希望我这样做。 这个过程仍然在内存中,但它似乎并没有被认为是一个Java过程。
有问题的服务器是Debian Lenny服务器,Java 6u14
/opt/jdk/bin# ./jmap -F -dump:format=b,file=/tmp/apidump.hprof 11175 Attaching to process ID 11175, please wait... sun.jvm.hotspot.debugger.NoSuchSymbolException: Could not find symbol "gHotSpotVMTypeEntryTypeNameOffset" in any of the known library names (libjvm.so, libjvm_g.so, gamma_g) at sun.jvm.hotspot.HotSpotTypeDataBase.lookupInProcess(HotSpotTypeDataBase.java:390) at sun.jvm.hotspot.HotSpotTypeDataBase.getLongValueFromProcess(HotSpotTypeDataBase.java:371) at sun.jvm.hotspot.HotSpotTypeDataBase.readVMTypes(HotSpotTypeDataBase.java:102) at sun.jvm.hotspot.HotSpotTypeDataBase.<init>(HotSpotTypeDataBase.java:85) at sun.jvm.hotspot.bugspot.BugSpotAgent.setupVM(BugSpotAgent.java:568) at sun.jvm.hotspot.bugspot.BugSpotAgent.go(BugSpotAgent.java:494) at sun.jvm.hotspot.bugspot.BugSpotAgent.attach(BugSpotAgent.java:332) at sun.jvm.hotspot.tools.Tool.start(Tool.java:163) at sun.jvm.hotspot.tools.HeapDumper.main(HeapDumper.java:77) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at sun.tools.jmap.JMap.runTool(JMap.java:179) at sun.tools.jmap.JMap.main(JMap.java:110) Debugger attached successfully. sun.jvm.hotspot.tools.HeapDumper requires a java VM process/core!
解决scheme非常简单。 我以root身份运行jmap,但是我必须以启动jvm的用户身份运行它。 我现在要把我的头埋在耻辱之中。
我用相同的用户运行jmap和应用程序,仍然得到错误。
该解决scheme在jmap之前运行
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
比只是使用jmap,并会正常工作
jmap -heap 17210
未来的Google员工:
如果您在尝试运行jmap的过程中安装了JDK ,也会发生这种情况。
如果是这种情况,请重新启动java进程。
如果有人试图在Docker容器中获得Java应用程序的Heap Dump。 这是为我工作的唯一解决scheme:
docker exec <container-name> jcmd 1 GC.heap_dump /tmp/docker.hprof
它基本上使用jcmd转储pid = 1的进程堆
请参阅https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html
如果你只是跑步,会发生什么
./jmap -heap 11175
你确定应用程序的JVM和JMAP的JVM是一样的吗? (相同版本等)
我在安装了两个不同的OpenJdks的Linux机器上出现了相同的jmap错误。 首先,我安装了OpenJDK 1.6,然后安装了OpenJDK 1.7。
呼叫…
/usr/lib/jvm/java-1.7.0-openjdk-amd64/bin/java -XshowSettings:properties -version # produce the following output ... ... java.library.path = /usr/java/packages/lib/amd64 /usr/lib/x86_64-linux-gnu/jni /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu /usr/lib/jni /lib /usr/lib ... java version "1.7.0_65"
使用OpenJDK 1.7包含'/ usr / lib'*启动的程序包括首先安装的JDK的库(在我的情况下是OpenJDK 1.6。*)。 所以Java6和Java7的jmap版本失败了。
在改变了包含OpenJDK 1.7库的Java7程序开始之后…
/usr/lib/jvm/java-1.7.0-openjdk-amd64/bin/java -Djava.library.path=/usr/lib/jvm/java- \ 7-openjdk-amd64/jre/lib/amd64/server:/usr/java/packages/lib/amd64: \ /usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/ \ x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib ...
我能够访问jmap程序的Java 7版本。 但它需要一个sudo来运行。
您需要使用JVM附带的jmap。
对我而言,只是简单地用sudo发出命令,如下所示:
sudo jmap -heap 21797
我有同样的问题,我试图find在一个Docker容器内运行的进程中的内存泄漏。 我无法使用jmap,而是使用了这个:
jcmd <pid> GC.class_histogram
这给你一个内存中的对象列表。 并从Oracle文档:
build议使用最新的实用程序jcmd而不是jmap实用程序来增强诊断并降低性能开销。 https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks004.html
当这些工作都不工作,或者你不想改变敏感的操作系统标志,如ptrace_scope:
您可以使用jconsole / jvisualvm来触发堆转储,或者直接从控制台运行任何JMX客户端,因为您在需要转储的计算机上本地执行此操作,所以速度更快:
echo 'jmx_invoke -m com.sun.management:type=HotSpotDiagnostic dumpHeap heapdump-20160309.hprof false' | java -jar jmxsh.jar -h $LOCALHOST_OR_IP -p $JMX_PORT
对于这个例子,我使用了wget https://github.com/davr/jmxsh/raw/master/jmxsh.jar 。
按照以下步骤从Docker容器中获取线程和堆转储
- 运行下面的命令来打开容器。 请适当更改CONTAINER_NAME
docker exec -it CONTAINER_NAME bash
- 然后键入jps以查找所有Java应用程序的详细信息,并为您的应用程序提取PID
jps
-
然后运行下面的命令来获取线程转储。 请适当更改PID
jstack PID > threadDump.tdump
-
然后运行下面的命令来获取堆转储。 请适当更改PID
jmap -dump:live,format=b,file=heapDump.hprof PID
- 然后从Docker容器退出,通过运行以下命令从docker容器中下载threadDump.tdump和heapDump.hprof。 请适当更改CONTAINER_NAME
sudo docker cp CONTAINER_NAME:threadDump.tdump . sudo docker cp CONTAINER_NAME:heapDump.hprof .