为什么 JVM 会为同一个 class 发送多个 JVMTI ClassLoad 事件?
Why does the JVM send multiple JVMTI ClassLoad events for the same class?
我启用了 JVMTI ClassLoad 事件,这些事件应该在首次加载 class 时生成。我希望每个 class 加载一次,但对于某些 classes,它似乎会生成多次,例如这个我得到了两次:
ClassLoad: Ljava/util/concurrent/ThreadFactory; loaded by thread 1
ClassLoad: Ljava/util/concurrent/ThreadFactory; loaded by thread 1
在 systemDictionary.cpp
中,我发现了三个 JvmtiExport::post_class_load
,我认为这是负责执行回调(如果有)的代码。他们在
SystemDictionary::resolve_instance_class_or_null
SystemDictionary::parse_stream
SystemDictionary::define_instance_class
但我还不了解整个流程,因此不清楚为什么我会多次收到该事件。
我能做些什么来防止这种情况发生,还是我需要自己处理并调整代码以忽略同一事件的多个事件class?
活动看两遍就OK了。这意味着 class 解析在不同的 class 加载程序的上下文中发生两次。首先,它由 Bootstrap class 加载器解析,然后由系统 class 加载器解析 - sun.misc.Launcher.AppClassLoader
.
来自 的实用程序将阐明此类事件发生时的情况。
考虑一个简单的例子:
public class Test {
public void setThreadFactory(ThreadFactory factory) {
}
public static void main(String[] args) {
}
}
当启动器查找 public static void main()
时,它会为 public 方法创建 Method
对象,这会导致解析此类方法签名中的所有 classes .
第一个 ClassLoad 事件:
Class loaded: java/util/concurrent/ThreadFactory
- ClassLoad(_jvmtiEnv*, JNIEnv_*, _jobject*, _jclass*) + 0x69
- JvmtiExport::post_class_load(JavaThread*, Klass*) + 0x15b
- SystemDictionary::define_instance_class(instanceKlassHandle, Thread*) + 0x3cc
- SystemDictionary::find_or_define_instance_class(Symbol*, Handle, instanceKlassHandle, Thread*) + 0x35d
- SystemDictionary::load_instance_class(Symbol*, Handle, Thread*) + 0x20c
- SystemDictionary::resolve_instance_class_or_null(Symbol*, Handle, Handle, Thread*) + 0x78c
- JVM_FindClassFromBootLoader + 0x22b
- Java_java_lang_ClassLoader_findBootstrapClass + 0x9b
* java/lang/ClassLoader.findBootstrapClass @ -1
* java/lang/ClassLoader.findBootstrapClassOrNull @ 12
* java/lang/ClassLoader.loadClass @ 48
* java/lang/ClassLoader.loadClass @ 38
* sun/misc/Launcher$AppClassLoader.loadClass @ 81
* java/lang/ClassLoader.loadClass @ 3
* java/lang/Class.getDeclaredMethods0 @ -1
* java/lang/Class.privateGetDeclaredMethods @ 37
* java/lang/Class.privateGetMethodRecursive @ 2
* java/lang/Class.getMethod0 @ 16
* java/lang/Class.getMethod @ 13
* sun/launcher/LauncherHelper.validateMainClass @ 12
* sun/launcher/LauncherHelper.checkAndLoadMain @ 214
第二个:
Class loaded: java/util/concurrent/ThreadFactory
- ClassLoad(_jvmtiEnv*, JNIEnv_*, _jobject*, _jclass*) + 0x69
- JvmtiExport::post_class_load(JavaThread*, Klass*) + 0x15b
- SystemDictionary::resolve_instance_class_or_null(Symbol*, Handle, Handle, Thread*) + 0x87c
- SystemDictionary::resolve_or_fail(Symbol*, Handle, Handle, bool, Thread*) + 0x33
- get_mirror_from_signature(methodHandle, SignatureStream*, Thread*) + 0xc6
- Reflection::get_parameter_types(methodHandle, int, oopDesc**, Thread*) + 0x18e
- Reflection::new_method(methodHandle, bool, bool, Thread*) + 0xfc
- get_class_declared_methods_helper(JNIEnv_*, _jclass*, unsigned char, bool, Klass*, Thread*) + 0x479
- JVM_GetClassDeclaredMethods + 0xcb
* java/lang/Class.getDeclaredMethods0 @ -1
* java/lang/Class.privateGetDeclaredMethods @ 37
* java/lang/Class.privateGetMethodRecursive @ 2
* java/lang/Class.getMethod0 @ 16
* java/lang/Class.getMethod @ 13
* sun/launcher/LauncherHelper.validateMainClass @ 12
* sun/launcher/LauncherHelper.checkAndLoadMain @ 214
我启用了 JVMTI ClassLoad 事件,这些事件应该在首次加载 class 时生成。我希望每个 class 加载一次,但对于某些 classes,它似乎会生成多次,例如这个我得到了两次:
ClassLoad: Ljava/util/concurrent/ThreadFactory; loaded by thread 1
ClassLoad: Ljava/util/concurrent/ThreadFactory; loaded by thread 1
在 systemDictionary.cpp
中,我发现了三个 JvmtiExport::post_class_load
,我认为这是负责执行回调(如果有)的代码。他们在
SystemDictionary::resolve_instance_class_or_null
SystemDictionary::parse_stream
SystemDictionary::define_instance_class
但我还不了解整个流程,因此不清楚为什么我会多次收到该事件。
我能做些什么来防止这种情况发生,还是我需要自己处理并调整代码以忽略同一事件的多个事件class?
活动看两遍就OK了。这意味着 class 解析在不同的 class 加载程序的上下文中发生两次。首先,它由 Bootstrap class 加载器解析,然后由系统 class 加载器解析 - sun.misc.Launcher.AppClassLoader
.
来自
考虑一个简单的例子:
public class Test {
public void setThreadFactory(ThreadFactory factory) {
}
public static void main(String[] args) {
}
}
当启动器查找 public static void main()
时,它会为 public 方法创建 Method
对象,这会导致解析此类方法签名中的所有 classes .
第一个 ClassLoad 事件:
Class loaded: java/util/concurrent/ThreadFactory
- ClassLoad(_jvmtiEnv*, JNIEnv_*, _jobject*, _jclass*) + 0x69
- JvmtiExport::post_class_load(JavaThread*, Klass*) + 0x15b
- SystemDictionary::define_instance_class(instanceKlassHandle, Thread*) + 0x3cc
- SystemDictionary::find_or_define_instance_class(Symbol*, Handle, instanceKlassHandle, Thread*) + 0x35d
- SystemDictionary::load_instance_class(Symbol*, Handle, Thread*) + 0x20c
- SystemDictionary::resolve_instance_class_or_null(Symbol*, Handle, Handle, Thread*) + 0x78c
- JVM_FindClassFromBootLoader + 0x22b
- Java_java_lang_ClassLoader_findBootstrapClass + 0x9b
* java/lang/ClassLoader.findBootstrapClass @ -1
* java/lang/ClassLoader.findBootstrapClassOrNull @ 12
* java/lang/ClassLoader.loadClass @ 48
* java/lang/ClassLoader.loadClass @ 38
* sun/misc/Launcher$AppClassLoader.loadClass @ 81
* java/lang/ClassLoader.loadClass @ 3
* java/lang/Class.getDeclaredMethods0 @ -1
* java/lang/Class.privateGetDeclaredMethods @ 37
* java/lang/Class.privateGetMethodRecursive @ 2
* java/lang/Class.getMethod0 @ 16
* java/lang/Class.getMethod @ 13
* sun/launcher/LauncherHelper.validateMainClass @ 12
* sun/launcher/LauncherHelper.checkAndLoadMain @ 214
第二个:
Class loaded: java/util/concurrent/ThreadFactory
- ClassLoad(_jvmtiEnv*, JNIEnv_*, _jobject*, _jclass*) + 0x69
- JvmtiExport::post_class_load(JavaThread*, Klass*) + 0x15b
- SystemDictionary::resolve_instance_class_or_null(Symbol*, Handle, Handle, Thread*) + 0x87c
- SystemDictionary::resolve_or_fail(Symbol*, Handle, Handle, bool, Thread*) + 0x33
- get_mirror_from_signature(methodHandle, SignatureStream*, Thread*) + 0xc6
- Reflection::get_parameter_types(methodHandle, int, oopDesc**, Thread*) + 0x18e
- Reflection::new_method(methodHandle, bool, bool, Thread*) + 0xfc
- get_class_declared_methods_helper(JNIEnv_*, _jclass*, unsigned char, bool, Klass*, Thread*) + 0x479
- JVM_GetClassDeclaredMethods + 0xcb
* java/lang/Class.getDeclaredMethods0 @ -1
* java/lang/Class.privateGetDeclaredMethods @ 37
* java/lang/Class.privateGetMethodRecursive @ 2
* java/lang/Class.getMethod0 @ 16
* java/lang/Class.getMethod @ 13
* sun/launcher/LauncherHelper.validateMainClass @ 12
* sun/launcher/LauncherHelper.checkAndLoadMain @ 214