Jmap无法连接进行转储

时间:2010-05-26 14:39:47

标签: java jvm heap

我们有一个应用程序的公开测试版,偶尔会导致堆空间溢出。 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!

14 个答案:

答案 0 :(得分:82)

解决方案非常简单。我以root身份运行jmap,但是我必须以启动jvm的用户身份运行它。我现在会羞愧地隐藏自己的头脑。

答案 1 :(得分:30)

我正在使用同一个用户运行jmap和应用程序,但仍然收到错误。

解决方案是在jmap之前执行的命令

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

比只使用jmap并且可以正常工作

jmap -heap 17210

答案 2 :(得分:15)

未来Google员工:

如果您在尝试运行jmap的过程中安装了JDK ,也会发生这种情况。

如果是这种情况,请重启java进程。

答案 3 :(得分:11)

如果有人试图在Docker容器中获取Heap Dump of Java应用程序。 这是唯一对我有用的解决方案:

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

答案 4 :(得分:6)

如果你只是运行

会发生什么
./jmap -heap 11175 

您确定应用程序JVM与JMAP JVM完全相同吗? (相同版本等)

答案 5 :(得分:4)

按照以下步骤从docker容器中获取线程和Heap转储

  1. 运行以下命令以打入容器。请妥善更改CONTAINER_NAME
  2.    docker exec -it CONTAINER_NAME bash
    
    1. 然后键入jps以查找所有Java应用程序详细信息并为您的应用程序提取PID
    2. jps
      
      1. 然后运行以下命令获取线程转储。请适当更改PID

        jstack PID > threadDump.tdump 
        
      2. 然后运行以下命令以获取堆转储。请适当更改PID

      3.     jmap -dump:live,format=b,file=heapDump.hprof PID 
        
        1. 然后退出docker容器并通过运行以下命令从docker容器下载threadDump.tdump和heapDump.hprof。请妥善更改CONTAINER_NAME
        2.  sudo docker cp CONTAINER_NAME:threadDump.tdump .
           sudo docker cp CONTAINER_NAME:heapDump.hprof .
          

答案 6 :(得分:3)

您需要使用JVM附带的jmap。

答案 7 :(得分:2)

我在安装了两个不同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"

包括&#39; / usr / lib&#39;每个OpenJDK 1.7。*启动程序包括第一个安装的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 ...

我能够使用Java 7版本的jmap程序访问proccess。但它需要一个sudo来运行。

答案 8 :(得分:2)

对我来说有用的是简单地用sudo发出命令,如:

sudo jmap -heap 21797

答案 9 :(得分:2)

我有同样的问题,我试图在Docker容器内运行的进程中发现内存泄漏。我无法使用jmap,而是使用了这个:

jcmd <pid> GC.class_histogram 

这为您提供了内存中对象的列表。并从Oracle文档:

  

建议使用最新的实用程序jcmd而不是jmap实用程序来增强诊断并降低性能开销。 https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks004.html

答案 10 :(得分:2)

1.Execute "Docker ps", will give the container Id of all services and collect the container id foe TSC.
2.Execute "docker exec -it CONTAINER_ID bash" (replace CONTAINER_ID with TSC Container id)
3.Bash will come and then execute the "jps" on bash, that will give you the PID for process(it will be 1 for jar)
4.Execute the "jstack PID > threadDump.tdump"(replace PID with process id received in step 3, it should be 1)
5.Execute the "jmap -dump:format=b,file=heapDump.hprof PID"(replace PID with process id received in step 3, it should be 1)
6.Then we have to exit the bash using "exit" command
7.Execute "sudo docker cp CONTAINER_ID:heapDump.hprof ." from ec2 command line, that will copy the dump file on ec2 machine present working directory.
8.Execute "sudo docker cp CONTAINER_ID:threadDump.tdump ." from ec2 command line, that will copy the dump file on ec2 machine present working directory.

答案 11 :(得分:0)

如果这些都不起作用,或者您不想更改敏感的操作系统标记,例如ptrace_scope:

要么可以使用jconsole / jvisualvm到trigger heap dumps,要么直接从控制台运行任何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

答案 12 :(得分:0)

就我而言,它并不像检查用户那么简单:(

我有一个名为collectd-java的脚本,它调用jstat和jmap。我已经通过top检查了这个脚本是否由拥有JVM的用户按预期启动。但是,jstat给了我我需要的东西,jmap无法附加。这是脚本 - 回声的东西只是我需要呈现值的格式:

HOSTNAME="${COLLECTD_HOSTNAME:-localhost}"
INTERVAL="${COLLECTD_INTERVAL:-60}"
MAIN_CLASS="my.fully.qualified.MainClass"
PID=$(pgrep -f ${MAIN_CLASS})

get_jstat_classloaderdata() {
VALUE=`jstat -class $PID 1 1 | awk '{print $1}' | grep -vi loaded`
echo "PUTVAL \"$HOSTNAME/exec-cecoco/gauge-java_classloader_loaded\" interval=$INTERVAL N:$VALUE"

VALUE=`jstat -class $PID 1 1 | awk '{print $2}' | grep -vi bytes`
echo "PUTVAL \"$HOSTNAME/exec-cecoco/gauge-java_classloader_bytesload\" interval=$INTERVAL N:$VALUE"

VALUE=`jstat -class $PID 1 1 | awk '{print $3}' | grep -vi unload`
echo "PUTVAL \"$HOSTNAME/exec-cecoco/gauge-java_classloader_unloaded\" interval=$INTERVAL N:$VALUE"

VALUE=`jstat -class $PID 1 1 | awk '{print $4}' | grep -vi bytes`
echo "PUTVAL \"$HOSTNAME/exec-cecoco/gauge-java_classloader_bytesunload\" interval=$INTERVAL N:$VALUE"

VALUE=`jstat -class $PID 1 1 | awk '{print $5}' | grep -vi time`
echo "PUTVAL \"$HOSTNAME/exec-cecoco/gauge-java_classloader_time\" interval=$INTERVAL N:$VALUE"
}

get_jmap_heapdata() {
        VALUE=$(jmap -heap ${PID} | grep MinHeapFreeRatio |awk '{print $3}')
        echo "PUTVAL \"$HOSTNAME/exec-cecoco/gauge-jmap_minheapfreeratio\" interval=$INTERVAL N:$VALUE"

        VALUE=$(jmap -heap ${PID} | grep   MaxHeapFreeRatio|awk '{print $3}')
        echo "PUTVAL \"$HOSTNAME/exec-cecoco/gauge-jmap_maxheapfreeratio\" interval=$INTERVAL N:$VALUE"

        VALUE=$(jmap -heap ${PID} | grep   MaxHeapSize|awk '{print $3}')
        echo "PUTVAL \"$HOSTNAME/exec-cecoco/gauge-jmap_maxheapsize\" interval=$INTERVAL N:$VALUE"
}
##Do it
get_jmap_heapdata
get_jstat_classloaderdata

Jstat成功,jmap失败。有人理解吗?

答案 13 :(得分:0)

不确定当我docker exec -it进入运行centos7 systemd和Java服务的容器时,为什么普通的“ jmap”失败了,但是在jmap选项下面对我有用。谢谢: https://dkbalachandar.wordpress.com/2016/07/05/thread-dump-from-a-docker-container/

[root@b29924306cfe /]# jmap 170 Attaching to process ID 170, please wait... Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process: ptrace(PTRACE_ATTACH, ..) failed for 170: Operation not permitted sun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process: ptrace(PTRACE_ATTACH, ..) failed for 170: Operation not permitted

[root@b29924306cfe /]# jmap -dump:live,format=b,file=heapDump.hprof 170 Dumping heap to /heapDump.hprof ... Heap dump file created