#java #jvm-hotspot
Вопрос:
Я пытаюсь создать очень простой агент обслуживания точки доступа Java для сброса байт-кода одного конкретного загруженного метода. Это код моего агента :
package sun.jvm.hotspot.jdi;
import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Method;
import sun.jvm.hotspot.oops.Klass;
import sun.jvm.hotspot.memory.SystemDictionary;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;
public class GetBytecode extends Tool {
@Override
public void run() {
VM.getVM().getSystemDictionary().allClassesDo(new SystemDictionary.ClassVisitor() {
public void visit(Klass klass) {
if (klass.getName().asString().equals("MyDebugger")) {
Method method = ((InstanceKlass) klass).findMethod("sendMessage", "()V");
for (byte bc : method.getByteCode()) {
System.out.printf("x ", bc);
}
}
}
});
}
public static void main(String[] args) {
new GetBytecode().execute(args);
}
}
который я компилирую со следующей строкой:
javac --add-modules=jdk.hotspot.agent --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.memory.SystemDictionary=ALL-UNNAMED" --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.memory=ALL-UNNAMED" --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED" --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.tools=ALL-UNNAMED" --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.runtime=ALL-UNNAMED" --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.classfile=ALL-UNNAMED" *.java
Это устраняет проблемы с импортом, которые у меня были раньше, но похоже, что с JDK11 SystemVisitor.ClassVisitor
интерфейс больше не существует, так как я получаю ошибку при компиляции :
GetBytecode.java:14: error: cannot find symbol
VM.getVM().getSystemDictionary().allClassesDo(new SystemDictionary.ClassVisitor() {
^
symbol: class ClassVisitor
location: class SystemDictionary
1 error
Кроме того, я не могу найти ни одного документа в Интернете, что так расстраивает… См. javadoc
SystemDictionary в JDK8
SystemDictionary в JDK11
Любое исправление / обходной путь приветствуется 🙂
Ответ №1:
jdk.hotspot.agent
это внутренний модуль JDK, не являющийся частью какого-либо стандарта, не предназначенный для конечных пользователей и, следовательно, не документированный.
Как следствие, API этого модуля может быть произвольно изменен даже при незначительном обновлении JDK. Код, написанный для одной версии JDK, не обязательно должен быть совместим с другой версией JDK. Это вполне понятно, поскольку Агент работоспособности отражает внутренние структуры JVM, которые могут меняться (и меняются) от версии к версии.
Поэтому вам понадобится другой код для JDK 11. Это может выглядеть так:
import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Method;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;
public class GetBytecode extends Tool {
@Override
public void run() {
VM.getVM().getSystemDictionary().sharedDictionary().allEntriesDo((klass, loader) -> {
if (klass.getName().asString().equals("MyDebugger")) {
Method method = ((InstanceKlass) klass).findMethod("sendMessage", "()V");
for (byte bc : method.getByteCode()) {
System.out.printf("x ", bc);
}
}
}, null);
}
public static void main(String[] args) {
new GetBytecode().execute(args);
}
}