AttachNotSupportedException из-за отсутствия файла java_pid в Attach API

Создав собственный профилировщик, я использую API JVMTI для создания собственного агента библиотеки. Этот агент можно запустить вместе с JVM с помощью параметра добавления -agentlib. Кроме того, существует Attach API, который позволяет внедрить агент в запущенную JVM. Я хотел реализовать эту функцию для своего профилировщика, используя следующий код:

try {
    String pid = VirtualMachine.list().get(0).id();
    VirtualMachine vm = VirtualMachine.attach(pid);
    vm.loadAgentLibrary("agent");
} catch (AgentLoadException e1) {
    e1.printStackTrace();
} catch (AgentInitializationException e1) {
    e1.printStackTrace();
} catch (IOException e1) {
    e1.printStackTrace();
} catch (AttachNotSupportedException e) {
    e.printStackTrace();
}

Что он делает? Из всех доступных виртуальных машин (VirtualMachine.list()) я выбираю первый, присоединяюсь к нему и пытаюсь загрузить в него свой агент. Агент, в системах UNIX с именем libagent.so, можно найти, но при попытке загрузить агент вызывается следующее исключение:

com.sun.tools.attach.AttachNotSupportedException:
   Unable to open socket file:
      target process not responding or HotSpot VM not loaded.

Заглядывая в исходный код, это исключение вызывается, потому что он не может найти файл с именем .java_pid<pid>. Я не нашел много информации об этом виде файла в документации. Я часто слышал, что этот файл больше не используется, но я запускаю Java 1.6.

Я также пытался подключиться к другим JVM, на самом деле я сохранил этот процесс присоединения динамическим, по причинам тестирования я просто пытаюсь подключиться к любой JVM.


Это код, который приводит к исключению, взятому из sun.tools.attach: LinuxVirtualMachine.java:

    // Return the socket file for the given process.
    // Checks working directory of process for .java_pid<pid>. If not
    // found it looks in /tmp.
    private String findSocketFile(int pid) {
       // First check for a .java_pid<pid> file in the working directory
       // of the target process
       String fn = ".java_pid" + pid;
       String path = "/proc/" + pid + "/cwd/" + fn;
       File f = new File(path);
       if (!f.exists()) {
           // Not found, so try /tmp
           path = "/tmp/" + fn;
           f = new File(path);
           if (!f.exists()) {
               return null;            // not found
           }
       }
       return path;
   }

В нем говорится, что он ищет корень в каталоге /proc/<pid>. Глядя на набор изменений JDK7, кажется, что они вносят изменения в код JDK7 Изменения в LinuxVirtualMachine

Ответ 1

У меня возникла такая же проблема.

Исключение в потоке "main" com.sun.tools.attach.AttachNotSupportedException: невозможно открыть файл сокета: целевой процесс не отвечает или не загружен VM HotSpot

Было найдено решение, которое делает тяжелый поиск.

Первый ответ пришел http://www.jvmmonitor.org/doc/index.html. Появляется ошибка:

Если вы видите дополнительное сообщение "Не удается открыть файл сокета: target процесс не отвечает или Hotspot VM не загружен", либо ваш приложение не ответило на создание файла сокета, например /tmp/.java_pid1234 (например, из-за зависания, разрешения файловой системы) или JVM Monitor не смог найти созданный файл сокета (например, из-за ошибка 7009828).

Затем после некоторого поиска я нашел беседу о github для другого инструмента, который имел тот же симптом "Не удалось открыть файл сокета" (https://github.com/rhuss/jolokia/issues/34):

jgreen: вызвано: com.sun.tools.attach.AttachNotSupportedException: Не удалось открыть файл сокета: целевой процесс не отвечает или не загружен VM HotSpot

jgreen: right У меня есть работа, но только тогда, когда он нравится тому же пользователю, что и activemq. root не работает

Эта последняя часть была решением. Единственный способ, с помощью которого этот вызов .attach был бы успешным, заключался в запуске java-кода, который вызывает attach как тот же, что и тот, кому принадлежит процесс, запускающий jvm. В моем случае это был пользователь activemq.

System.out.println("HEAP: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage());

HEAP: init = 27127296(26491K) used = 3974200(3881K) committed = 26345472(25728K) max = 675086336(659264K)

Ответ 2

Я подозреваю, что вы можете указать -Djava.io.tmpdir для вашей JVM-версии, а также на Java 6 Update 23 или 24. Если вам нужно просто обновить до 25 обновления для запущенного экземпляра.

Единственная ссылка на эту проблему, которую я видел, - это Jstack и Jstat перестали работать с обновлением до JDK6u23. Я определенно видел ту же проблему с обновлением 23 и неудачей jstack, где он работал нормально до 23 и снова работает с 25. Я также просто попробовал VirtualMachine.attach(pid) против 23, и он терпит неудачу, если используется -Djava.io.tmpdir. Он работает с 25.