Ответ 1
Решение было очень простым. Я запускал jmap как root, но мне приходилось запускать его как пользователя, который начал jvm. Теперь я скрою голову от стыда.
У нас есть открытая бета-версия приложения, которое иногда приводит к переполнению кучи. 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 как root, но мне приходилось запускать его как пользователя, который начал jvm. Теперь я скрою голову от стыда.
Я запускал jmap и приложение с тем же пользователем и все еще получаю ошибку.
Решение было выполнено с точностью до jmap
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
Чем просто использовать jmap и будет отлично работать
jmap -heap 17210
Будущие гуглеры:
Это также может произойти, если вы установили JDK, пока процесс jmap был запущен.
Если это произойдет, перезапустите 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? (та же версия и т.д.)
Я получил ту же ошибку jmap на Linux-машине, у которой установлены два разных OpenJdks. Сначала я установил 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"
С включением '/usr/lib' каждый с OpenJDK 1.7. * запущенная программа включает в себя библиотеки первого установленного JDK (в моем случае OpenJDK 1.6. *). Таким образом, jmap-версии Java6 и Java7 не удались.
После того, как я изменил старт для Java7-программ с включенными библиотеками OpenJDK 1.7...
/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-версии jmap-программы. Но для этого требуется sudo.
Вам нужно использовать jmap, который поставляется с JVM.
Что сработало для меня было просто выдать команду с sudo, как в:
sudo jmap -heap 21797
У меня такая же проблема, я пытаюсь найти утечку памяти в процессе, запущенном внутри контейнера Docker. Я не смог использовать jmap, вместо этого я использовал это:
jcmd <pid> GC.class_histogram
Это дает вам список объектов в памяти. И из документации Oracle:
Рекомендуется использовать последнюю утилиту jcmd вместо утилиты jmap для расширенной диагностики и снижения издержек производительности. https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks004.html
Следуйте приведенным ниже инструкциям, чтобы взять поток и кучи кучи из контейнера докеров
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 .
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.
Если ни одна из этих функций не работает или вы не хотите изменять уязвимые флагов ОС, такие как 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 для этого примера.