Как перехватить создание объекта в Java ниже уровня пользовательского класса

Я смотрю на какой-то подход, в котором с помощью агента Java или классов инструментов (желательно что-то на более низком уровне, чем пользовательские классы) перехватить все объекты создания в JVM (new или любые альтернативные способы создания объекта), есть похожий вопрос, который не фокусируется на агенте Java или что-то более низкое, чем инструментарий пользовательских классов

2 ответа

Решение

Объекты Java могут быть созданы несколькими различными способами.

  1. Из кода Java, когда метод Java, интерпретированный или скомпилированный, выполняет одну из следующих инструкций байт-кода: new, newarray, anewarray, multianewarray,
  2. Из нативного кода, когда нативные методы, в том числе из стандартной библиотеки классов, вызывают одну из функций JNI: NewObject, NewObjectArray, NewStringUTF, NewDirectByteBuffer, так далее.
  3. Непосредственно из среды выполнения виртуальной машины, когда JVM создает новый объект внутренне, например, в ответ на Object.clone(), Throwable.getStackTrace(), Class.getInterfaces(), так далее.

К сожалению, нет единой точки, где вы можете собирать объекты из всех этих источников. Однако есть средства для их перехвата.

  1. Объекты, созданные в Java, могут быть пойманы агентом Instrumentation. Агент должен определить ClassFileTransformer, который будет сканировать байт-код всех загруженных классов для инструкций по созданию объекта и изменять его.

    Примечание: нет необходимости перехватывать все new инструкции, вы можете инструмент Object() конструктор вместо. Но вам все еще нужно перехватить инструкции по размещению массива.

  2. Функции JNI могут быть перехвачены агентом JVMTI. Вам нужно определить свои собственные нативные хуки для NewObjectArray, NewStringUTF и т.д., а затем заменить таблицу функций JNI. Смотрите JVMTI Ссылка для деталей.

  3. Объекты, созданные виртуальной машиной, могут быть перехвачены механизмом обратного вызова событий JVMTI. Желаемое событие - VMObjectAlloc.

    Примечание: JVM не будет публиковать VMObjectAlloc событие для объектов, выделенных из Java или функций JNI.

Все остальные способы создания объектов (клонирование, отражение, десериализация) попадают в одну из вышеуказанных категорий.


Загрузите демонстрационные материалы и образцы JDK 8 с веб-сайта Oracle Java SE Downloads.
Для этого вопроса есть образец агента JVMTI.

Смотреть под

  • jvmti/heapTracker
  • jvmti/hprof

Вы можете взглянуть на этот Java-агент с открытым исходным кодом, созданный командой devexperts https://github.com/Devexperts/aprof Он предоставляет хорошие отчеты, чтобы определить, где выделена память. Но, как я знаю, он не перехватывает новые объекты, созданные с помощью JNI или sun.misc.Unsafe.allocateInstance в текущей версии

Это чистый Java-агент, который манипулирует байт-кодом с ASM. Перед каждым выделением объекта aprof вставляет вызов метода, который отслеживает размер выделения и стек расположения (где происходит это выделение)

Другие вопросы по тегам