Linux

Запуск jmap, получение которого невозможно без открытия файла сокета

Я запустил jmap, чтобы сделать дамп кучи моего процесса, но jvm выдал ответ:

Невозможно открыть файл сокета: целевой процесс не отвечает или HotSpot VM не загружена

Опция -F может быть использована, когда целевой процесс не отвечает

 Пара вопросов:

  1. Использование -F нормально для получения дампа кучи?

  2. Я подождал 20 минут, и процесс не остановился. Есть идеи, почему так?

Ответ 1

jmap vs. jmap -F, а также jstack vs. jstack -F используют совершенно разные механизмы для связи с целевой JVM.

jmap / jstack

При запуске без -F эти инструменты используют механизм динамического присоединения. Это работает следующим образом:

  1. Перед подключением к Java-процессу 1234 jmap создает файл .attach_pid1234 в рабочем каталоге целевого процесса или в /tmp.

  2. Затем jmap посылает SIGQUIT целевому процессу. Когда JVM перехватывает сигнал и находит .attach_pid1234, она запускает поток AttachListener.

  3. Поток AttachListener создает сокет домена UNIX /tmp/.java_pid1234 для прослушивания команд от внешних инструментов.

  4. В целях безопасности, когда принимается соединение (от jmap), JVM проверяет, что учетные данные пира сокета равны euid и egid процесса JVM. Поэтому jmap не будет работать, если его запустит другой пользователь (даже root).

  5. jmap подключается к сокету и посылает команду dumpheap.

  6. Эта команда считывается и выполняется потоком AttachListener JVM. Весь вывод отправляется обратно в сокет. Поскольку дамп кучи делается в процессе непосредственно JVM, операция выполняется очень быстро, однако JVM может делать это только в безопасных соединениях. Если соединение безопасности не может быть достигнуто (например, процесс завис, не отвечает, или идет длительный GC), jmap возьмет таймаут и завершится неудачей.

 Давайте подытожим преимущества и недостатки Dynamic Attach.

Плюсы:

  1. Дамп кучи и другие операции выполняются JVM совместно с максимальной скоростью.

  2. Вы можете использовать любую версию jmap или jstack для подключения к любой другой версии JVM.

Минусы:

  1. Инструмент должен быть запущен тем же пользователем (euid/egid), что и целевая JVM.

  2. Может использоваться только на живой и активной JVM.

  3. Не будет работать, если целевая JVM запущена с параметром -XX:+DisableAttachMechanism.

jmap -F / jstack -F

  1. При запуске с параметром -F программа переходит в специальный режим, в котором работает HotSpot Serviceability Agent. В этом режиме целевой процесс замораживается; инструменты читают его память с помощью средств отладки ОС, а именно ptrace в Linux.

  2. jmap -F вызывает PTRACE_ATTACH на целевой JVM. Целевой процесс безоговорочно приостанавливается в ответ на сигнал SIGSTOP.

  3. Программа читает память JVM, используя PTRACE_PEEKDATA. ptrace может читать только одно слово за раз, поэтому для чтения большой кучи целевого процесса требуется слишком много вызовов. Это очень и очень медленно.

  4. Инструмент реконструирует внутренние структуры JVM, основываясь на знании конкретной версии JVM. Поскольку разные версии JVM имеют разную компоновку памяти, режим -F работает, только если jmap из того же JDK, что и целевой Java-процесс.

  5. Инструмент сам создает дамп кучи, а затем возобновляет работу целевого процесса.

Плюсы:

  1. Не требуется никакого коннекта с целевой JVM. Можно использовать даже на зависшем процессе.

  2. ptrace работает всегда, когда достаточно привилегий на уровне ОС. Например, root может делать дамп процессов всех других пользователей.

Минусы:

  1. Очень медленно для больших куч.

  2. Инструмент и целевой процесс должны быть из одной и той же версии JDK.

  3. Безопасное соединение не гарантируется, если инструмент подключается в принудительном режиме. Хотя jmap пытается обработать все особые случаи, иногда может получиться так, что целевая JVM не находится в согласованном состоянии.

Примечание

Существует более быстрый способ получения дампов кучи в принудительном режиме. Сначала создайте дамп кучи с помощью gcore, а затем запустите jmap над сгенерированным файлом кучи. 

Ответ 2

Если ваше приложение работает как служба systemd, вам следует открыть файл службы, который находится в каталоге /usr/lib/systemd/system/ и назван именем вашей службы. Затем проверьте, является ли атрибут privateTmp как true.

Если это так, вы должны изменить его на false, а затем обновить сервис командой, как показано ниже: 

systemctl daemon-reload

systemctl restart [servicename].

Если вы хотите запустить jmap/jcmd перед перезапуском, вы можете воспользоваться скриптом execStop в файле службы. Просто поместите в него команду и выполните systemctl stop [имя службы].

 

Схожие статьи

Linux

Как сделать переадресацию портов с одного IP на другой в одной и той же сети?

Linux

Какой самый простой способ отправить зашифрованное письмо?

Linux

Как я могу создать символическую ссылку на файл в Linux

Linux

Как узнать, взломан ли мой Linux-сервер?