アプリのオープンベータ版があり、それによってヒープ領域がオーバーフローすることがあります。 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!
解決策は非常に簡単でした。ルートとしてjmapを実行していましたが、jvmを起動したユーザーとして実行する必要がありました。恥ずかしげに頭を隠していきます。
同じユーザーでjmapとアプリケーションを実行していても、エラーが発生します。
Jmapの前にコマンドが実行されたソリューション
echo 0 | Sudo tee /proc/sys/kernel/yama/ptrace_scope
Jmapを使用しているだけで問題なく動作します
jmap -heap 17210
今後のGoogle社員:
これは、jmapを実行しようとしているプロセスが実行されているときにJDKをインストールした場合whileにも発生する可能性があります。
その場合は、Javaプロセスを再起動します。
誰かがJava Dockerコンテナ内のアプリケーションのヒープダンプを取得しようとする場合、これが私にとって有効な唯一のソリューションです。
docker exec <container-name> jcmd 1 GC.heap_dump /tmp/docker.hprof
基本的にpid = 1でプロセスのヒープをダンプしますjcmd
https://docs.Oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html を参照してください
走ったらどうなる
./jmap -heap 11175
また、アプリケーションJVMはJMAP JVMと同一ですか? (同じバージョンなど)
以下の手順に従って、ドッカーコンテナからスレッドとヒープダンプを取得します
docker exec -it CONTAINER_NAME bash
jps
次に、以下のコマンドを実行してスレッドダンプを取得します。 PIDを適切に変更してください
jstack PID > threadDump.tdump
次に、以下のコマンドを実行してヒープダンプを取得します。 PIDを適切に変更してください
jmap -dump:live,format=b,file=heapDump.hprof PID
Sudo docker cp CONTAINER_NAME:threadDump.tdump . Sudo docker cp CONTAINER_NAME:heapDump.hprof .
JVMに付属のjmapを使用する必要があります。
2つの異なる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 ...
Java 7バージョンのjmapプログラムでプロセスにアクセスできました。しかし、実行するにはSudoが必要です。
私は同じ問題を抱えています。Dockerコンテナ内で実行されているプロセスでメモリリークを見つけようとしています。私はjmapを使用できませんでしたが、代わりにこれを使用しました:
jcmd <pid> GC.class_histogram
これにより、メモリ内のオブジェクトのリストが表示されます。 Oracleのドキュメントから:
診断を強化し、パフォーマンスのオーバーヘッドを減らすために、jmapユーティリティの代わりに最新のユーティリティであるjcmdを使用することをお勧めします。 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.
私のために働いたのは、次のようにSudoでコマンドを発行するだけでした:
Sudo jmap -heap 21797
私の場合、ユーザーを確認するほど簡単ではありません:(
Jstatとjmapを呼び出すcollectd-Javaというスクリプトがあります。そのようなスクリプトは、予想どおり、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は失敗します。誰もがそれを理解していますか?
これらのいずれも機能しない場合、またはptrace_scopeなどの重要なOSフラグを変更したくない場合:
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 を使用しました。
Centos7 systemdとJavaサービスを実行しているコンテナに_docker exec -it
_)を実行すると、プレーンな "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
_