programing

Jmap은 덤프를 만들기 위해 연결할 수 없습니다.

shortcode 2021. 1. 16. 20:22
반응형

Jmap은 덤프를 만들기 위해 연결할 수 없습니다.


때때로 힙 공간이 오버플로되는 앱의 오픈 베타가 있습니다. JVM은 영구적 인 휴가를 통해 반응합니다.

이것을 분석하기 위해 실패한 지점의 기억을 들여다보고 싶습니다. Java는이 작업을 원하지 않습니다. 프로세스는 여전히 메모리에 있지만 Java 프로세스로 인식되지 않는 것 같습니다.

문제의 서버는 데비안 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!

해결책은 매우 간단했습니다. jmap을 루트로 실행하고 있었지만 jvm을 시작한 사용자로 실행해야했습니다. 이제 부끄러워서 머리를 감추겠습니다.


동일한 사용자로 jmap과 응용 프로그램을 실행했지만 여전히 오류가 발생합니다.

솔루션은 jmap 전에 해당 명령을 실행했습니다.

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

jmap을 사용하는 것보다 잘 작동합니다.

jmap -heap 17210

향후 Google 직원 :

jmap하려는 프로세스가 실행되는 동안 JDK를 설치 한 경우에도 발생할 수 있습니다 .

이 경우 Java 프로세스를 다시 시작하십시오.


누군가 Docker 컨테이너에서 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을 참조 하십시오.


방금 실행하면 어떻게 되나요?

./jmap -heap 11175 

그리고 애플리케이션 JVM이 JMAP JVM과 동일하다고 확신합니까? (동일 버전 등)


아래 단계에 따라 도커 컨테이너에서 스레드 및 힙 덤프를 가져옵니다.

  1. 아래 명령을 실행하여 컨테이너로 bash. CONTAINER_NAME을 적절하게 변경하십시오.
   docker exec -it CONTAINER_NAME bash
  1. 그런 다음 jps를 입력하여 모든 Java 애플리케이션 세부 정보를 찾고 애플리케이션의 PID를 추출합니다.
jps
  1. 그런 다음 아래 명령을 실행하여 스레드 덤프를 가져옵니다. PID를 적절하게 변경하십시오

    jstack PID > threadDump.tdump 
    
  2. 그런 다음 아래 명령을 실행하여 힙 덤프를 가져옵니다. PID를 적절하게 변경하십시오

    jmap -dump:live,format=b,file=heapDump.hprof PID 
  1. 그런 다음 도커 컨테이너를 종료하고 아래 명령을 실행하여 도커 컨테이너에서 threadDump.tdump 및 heapDump.hprof를 다운로드합니다. CONTAINER_NAME을 적절하게 변경하십시오.
 sudo docker cp CONTAINER_NAME:threadDump.tdump .
 sudo docker cp CONTAINER_NAME:heapDump.hprof .

JVM과 함께 제공되는 jmap을 사용해야합니다.


두 개의 다른 OpenJdk가 설치된 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가 필요합니다.


나를 위해 일한 것은 다음과 같이 sudo로 명령을 실행하는 것입니다.

sudo jmap -heap 21797

동일한 문제가 있습니다. Docker 컨테이너 내부에서 실행되는 프로세스에서 메모리 누수를 찾으려고합니다. 나는 jmap을 사용할 수 없었고 대신 이것을 사용했습니다.

jcmd <pid> GC.class_histogram 

이것은 당신에게 메모리의 객체 목록을 제공합니다. 그리고 Oracle 문서에서 :

It is recommended to use the latest utility, jcmd instead of jmap utility for enhanced diagnostics and reduced performance overhead. https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks004.html


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.

When none of these work or if you don't want to change sensitive OS flags such as ptrace_scope:

Either you can use jconsole/jvisualvm to trigger heap dumps or run any JMX client directly from console as follows as you are doing it locally on the machine that needs the dump and so is faster:

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

I used the wget https://github.com/davr/jmxsh/raw/master/jmxsh.jar for this example.


In my case it is not as simple as check the user :(

I have a script called collectd-java which invokes jstat and jmap. I've checked by top that such script is launched, as expected, by the user owning the JVM. However, jstat gives me what I need and jmap can't attach. Here is the script - the echo stuff is just the format I need to present the values:

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 succeeds and jmap fails. Does anyone understands it ?


Not sure why a plain "jmap " fails when I docker exec -it into my container running centos7 systemd and a java service, but below jmap options worked for me. Thanks: 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

ReferenceURL : https://stackoverflow.com/questions/2913948/jmap-cant-connect-to-make-a-dump

반응형