• Java的反射慢在哪?


    有些人说反射很慢,但是也没有人真正地测试过。spring的代码里有好多使用反射的地方,所以性能应该也没有那么差。

    本文就来挖一挖反射的实现原理以及可能导致的问题。

    简单使用

    简单地用反射的方式获取一个field的属性:

    1. "prettyprint hljs gradle" deep="7" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@RunWith(JUnit4ClassRunner.class)
    2. public class ReflectTest {
    3. public int count = 10;
    4. public int getCount() {
    5. try {
    6. // 为了查看调用栈
    7. new RuntimeException().printStackTrace();
    8. } catch (Throwable ignore) {
    9. }
    10. return count;
    11. }
    12. private void setCount(int count) {
    13. this.count = count;
    14. }
    15. @Test
    16. @SneakyThrows
    17. public void testReflection() {
    18. Class clazz = Class.forName("com.air.lang.reflect.ReflectTest");
    19. Method getCountMethod = clazz.getDeclaredMethod("getCount", null);
    20. final Object instance = clazz.newInstance();
    21. final Object o = getCountMethod.invoke(instance);
    22. System.out.println("o = " + o);
    23. }
    24. }

    运行起来(-XX:+TraceClassLoading ),输出如下:

    1. class="prettyprint hljs scheme" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">[Loaded sun.reflect.NativeMethodAccessorImpl from /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/rt.jar]
    2. [Loaded sun.reflect.DelegatingMethodAccessorImpl from /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/rt.jar]
    3. java.lang.RuntimeException
    4. at com.air.lang.reflect.ReflectTest.getCount(ReflectTest.java:21)
    5. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    6. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    7. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    8. at java.lang.reflect.Method.invoke(Method.java:498)
    9. at com.air.lang.reflect.ReflectTest.testReflection(ReflectTest.java:82)
    10. // 下面是junit用反射调用这个方法的栈
    11. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    12. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    13. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    14. at java.lang.reflect.Method.invoke(Method.java:498)
    15. at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
    16. o = 10

    从调用栈可以看到,Method的invoke的调用路径:

    DelegatingMethodAccessorImpl -> NativeMethodAccessorImpl

    翻下invoke的实现:

    1. "prettyprint hljs perl" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">// java.lang.reflect.Method#invoke
    2. @CallerSensitive
    3. public Object invoke(Object obj, Object... args)
    4. throws IllegalAccessException, IllegalArgumentException,
    5. InvocationTargetException
    6. {
    7. if (!override) {
    8. if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
    9. Class caller = Reflection.getCallerClass();
    10. checkAccess(caller, clazz, obj, modifiers);
    11. }
    12. }
    13. MethodAccessor ma = methodAccessor; // read volatile
    14. if (ma == null) {
    15. ma = acquireMethodAccessor();
    16. }
    17. return ma.invoke(obj, args);
    18. }

    最终调用是委托给了MethodAccessor,这是java中的一个接口:

    1. class="prettyprint hljs typescript" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">// sun.reflect.MethodAccessor
    2. /** This interface provides the declaration for
    3. java.lang.reflect.Method.invoke(). Each Method object is
    4. configured with a (possibly dynamically-generated) class which
    5. implements this interface.
    6. */
    7. public interface MethodAccessor {
    8. /** Matches specification in {@link java.lang.reflect.Method} */
    9. public Object invoke(Object obj, Object[] args)
    10. throws IllegalArgumentException, InvocationTargetException;
    11. }

    实现类有三个,DelegatingMethodAccessorImpl是代理模式,主要是为了切换底层的实现。因此主要的实现就两种,一个是MethodAccessorImpl,一个是NativeMethodAccessorImpl。

    <pre class="prettyprint hljs sql" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Delegates its invocation to another MethodAccessorImpl and can change its delegate at run time.
    

    简单测试下时间

    1. "prettyprint hljs gradle" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@SneakyThrows
    2. public void testReflection() {
    3. Class clazz = Class.forName("com.air.lang.reflect.ReflectTest");
    4. Method getCountMethod = clazz.getDeclaredMethod("getCount", null);
    5. final Object instance = clazz.newInstance();
    6. for (int i = 0; i < 20; i++) {
    7. // 注意,这里是nano time
    8. final long start = System.nanoTime();
    9. final Object o = getCountMethod.invoke(instance);
    10. System.out.println(i + 1 + ": cost " + (System.nanoTime() - start));
    11. }
    12. System.in.read();
    13. }
    1. <pre class="prettyprint hljs http" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">1: cost 19792
    2. 2: cost 3625
    3. 3: cost 2583
    4. 4: cost 2333
    5. 5: cost 3250
    6. 6: cost 4166
    7. 7: cost 2459
    8. 8: cost 27041
    9. 9: cost 7875
    10. 10: cost 7500
    11. 11: cost 8167
    12. 12: cost 7500
    13. 13: cost 7250
    14. 14: cost 7459
    15. 15: cost 7750
    16. 16: cost 1085417
    17. 17: cost 7208
    18. 18: cost 2500
    19. 19: cost 1917
    20. 20: cost 2292

    注意看,第1次调用和第16次调用,时间都比较长。inflation的默认阈值是15,超过15之后就会转为动态字节码生成的方式,中间要生成字节码,所以耗时较高,之后耗时就降下来了。

    两种实现方式

    Before Java 1.4 Method.invoke worked through a JNI call to VM runtime.

    Since Java 1.4 Method.invoke uses dynamic bytecode generation if a method is called more than 15 times (configurable via sun.reflect.inflationThreshold system property).

    Java 1.4之前都是使用Native的方式调用,1.4之后,会根据调用的阈值做优化,超过一定的阈值 -Dsun.reflect.inflationThreshold ,会转换成dynamic bytecode generation的方式。dynamic bytecode generation的性能会更好。

    Native实现

    1. class="prettyprint hljs typescript" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">// sun.reflect.NativeMethodAccessorImpl#invoke
    2. public Object invoke(Object obj, Object[] args)
    3. throws IllegalArgumentException, InvocationTargetException
    4. {
    5. // We can't inflate methods belonging to vm-anonymous classes because
    6. // that kind of class can't be referred to by name, hence can't be
    7. // found from the generated bytecode.
    8. if (++numInvocations > ReflectionFactory.inflationThreshold()
    9. && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
    10. MethodAccessorImpl acc = (MethodAccessorImpl)
    11. // 超过阈值之后,会切换成动态字节码的方式
    12. // 注意,这里没有加锁
    13. new MethodAccessorGenerator().
    14. generateMethod(method.getDeclaringClass(),
    15. method.getName(),
    16. method.getParameterTypes(),
    17. method.getReturnType(),
    18. method.getExceptionTypes(),
    19. method.getModifiers());
    20. // parent就是刚才说的代理DelegatingMethodAccessorImpl
    21. // 生成结束之后,这里切换成新的调用方式
    22. parent.setDelegate(acc);
    23. }
    24. // 这里是native方法
    25. return invoke0(method, obj, args);
    26. }
    27. void setParent(DelegatingMethodAccessorImpl parent) {
    28. this.parent = parent;
    29. }
    30. private static native Object invoke0(Method m, Object obj, Object[] args);

    去jdk的代码里看看这个nativev方法的实现:

    1. "prettyprint hljs livescript" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">// NativeAccessors.c
    2. JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_NativeMethodAccessorImpl_invoke0
    3. (JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args)
    4. {
    5. return JVM_InvokeMethod(env, m, obj, args);
    6. }
    7. // jvm.cpp
    8. JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0))
    9. Handle method_handle;
    10. if (thread->stack_overflow_state()->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) {
    11. method_handle = Handle(THREAD, JNIHandles::resolve(method));
    12. Handle receiver(THREAD, JNIHandles::resolve(obj));
    13. objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
    14. oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL);
    15. jobject res = JNIHandles::make_local(THREAD, result);
    16. if (JvmtiExport::should_post_vm_object_alloc()) {
    17. oop ret_type = java_lang_reflect_Method::return_type(method_handle());
    18. assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!");
    19. if (java_lang_Class::is_primitive(ret_type)) {
    20. // Only for primitive type vm allocates memory for java object.
    21. // See box() method.
    22. JvmtiExport::post_vm_object_alloc(thread, result);
    23. }
    24. }
    25. return res;
    26. } else {
    27. THROW_0(vmSymbols::java_lang_StackOverflowError());
    28. }
    29. JVM_END
    30. // reflection.cpp
    31. // This would be nicer if, say, java.lang.reflect.Method was a subclass
    32. // of java.lang.reflect.Constructor
    33. oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) {
    34. oop mirror = java_lang_reflect_Method::clazz(method_mirror);
    35. int slot = java_lang_reflect_Method::slot(method_mirror);
    36. bool override = java_lang_reflect_Method::override(method_mirror) != 0;
    37. objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Method::parameter_types(method_mirror)));
    38. oop return_type_mirror = java_lang_reflect_Method::return_type(method_mirror);
    39. BasicType rtype;
    40. if (java_lang_Class::is_primitive(return_type_mirror)) {
    41. rtype = basic_type_mirror_to_basic_type(return_type_mirror);
    42. } else {
    43. rtype = T_OBJECT;
    44. }
    45. InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror));
    46. Method* m = klass->method_with_idnum(slot);
    47. if (m == NULL) {
    48. THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke");
    49. }
    50. methodHandle method(THREAD, m);
    51. return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD);
    52. }

    invoke方法就比较复杂了,这里就不跟进了,可以看到native的实现就是使用JNI调用,然后利用jvm内部的数据结构完成方法的调用。

    dynamic bytecode generation

    class="hljs delphi" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">The approach with dynamic bytecode generation is much faster since it
    
    • does not suffer from JNI overhead ;
    • does not need to parse method signature each time, because each method invoked via Reflection has its own unique MethodAccessor ;
    • can be further optimized, e.g. these MethodAccessors can benefit from all regular JIT optimizations like inlining, constant propagation, autoboxing elimination etc.
    • Note, that this optimization is implemented mostly in Java code without JVM assistance. The only thing HotSpot VM does to make this optimization possible - is skipping bytecode verification for such generated MethodAccessors. Otherwise the verifier would not allow, for example, to call private methods.

    稍微改造下代码:

    1. "prettyprint hljs dart" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Test
    2. @SneakyThrows
    3. public void testReflection() {
    4. Class clazz = Class.forName("com.air.lang.reflect.ReflectTest");
    5. Method getCountMethod = clazz.getDeclaredMethod("getCount", null);
    6. final Object instance = clazz.newInstance();
    7. for (int i = 0; i < 20; i++) {
    8. final Object o = getCountMethod.invoke(instance);
    9. System.out.println("o = " + o);
    10. }
    11. // 阻塞退出,等待输入
    12. System.in.read();
    13. }

    程序跑起来之后,反复调用了20次,超过了默认的阈值,会自动生成字节码。

    第一次输出的调用栈:

    1. class="prettyprint hljs css" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">java.lang.RuntimeException
    2. at com.air.lang.reflect.ReflectTest.getCount(ReflectTest.java:21)
    3. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    4. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    5. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    6. at java.lang.reflect.Method.invoke(Method.java:498)
    7. at com.air.lang.reflect.ReflectTest.testReflection(ReflectTest.java:83)

    最后一次输出的调用栈:

    1. class="prettyprint hljs css" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">java.lang.RuntimeException
    2. at com.air.lang.reflect.ReflectTest.getCount(ReflectTest.java:21)
    3. at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    4. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    5. at java.lang.reflect.Method.invoke(Method.java:498)
    6. at com.air.lang.reflect.ReflectTest.testReflection(ReflectTest.java:83)

    调用栈发生了变化, 从NativeMethodAccessorImpl变为了GeneratedMethodAccessor1

    我们用arthas找下生成的字节码:

    1. class="prettyprint hljs ruby" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">[arthas@45767]$ sc -d *GeneratedMethodAccessor1
    2. class-info sun.reflect.GeneratedMethodAccessor1
    3. code-source
    4. name sun.reflect.GeneratedMethodAccessor1
    5. isInterface false
    6. isAnnotation false
    7. isEnum false
    8. isAnonymousClass false
    9. isArray false
    10. isLocalClass false
    11. isMemberClass false
    12. isPrimitive false
    13. isSynthetic false
    14. simple-name GeneratedMethodAccessor1
    15. modifier public
    16. annotation
    17. interfaces
    18. super-class +-sun.reflect.MethodAccessorImpl
    19. +-sun.reflect.MagicAccessorImpl
    20. +-java.lang.Object
    21. class-loader +-sun.reflect.DelegatingClassLoader@57fa26b7
    22. +-sun.misc.Launcher$AppClassLoader@18b4aac2
    23. +-sun.misc.Launcher$ExtClassLoader@6d3a7064
    24. classLoaderHash 57fa26b7
    25. Affect(row-cnt:1) cost in 29 ms.

    反编译下看看生成的类:

    1. class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">[arthas@45767]$ jad sun.reflect.GeneratedMethodAccessor1
    2. ClassLoader:
    3. +-sun.reflect.DelegatingClassLoader@57fa26b7
    4. +-sun.misc.Launcher$AppClassLoader@18b4aac2
    5. +-sun.misc.Launcher$ExtClassLoader@6d3a7064
    6. Location:
    7. /*
    8. * Decompiled with CFR.
    9. *
    10. * Could not load the following classes:
    11. * com.air.lang.reflect.ReflectTest
    12. */
    13. package sun.reflect;
    14. import com.air.lang.reflect.ReflectTest;
    15. import java.lang.reflect.InvocationTargetException;
    16. import sun.reflect.MethodAccessorImpl;
    17. public class GeneratedMethodAccessor1
    18. extends MethodAccessorImpl {
    19. /*
    20. * Loose catch block
    21. */
    22. public Object invoke(Object object, Object[] objectArray) throws InvocationTargetException {
    23. ReflectTest reflectTest;
    24. block5: {
    25. if (object == null) {
    26. throw new NullPointerException();
    27. }
    28. // 这里直接强转了,把Object类型转成了目标类型ReflectTest
    29. reflectTest = (ReflectTest)object;
    30. if (objectArray == null || objectArray.length == 0) break block5;
    31. throw new IllegalArgumentException();
    32. }
    33. try {
    34. // 调用对应的方法
    35. return new Integer(reflectTest.getCount());
    36. }
    37. catch (Throwable throwable) {
    38. throw new InvocationTargetException(throwable);
    39. }
    40. catch (ClassCastException | NullPointerException runtimeException) {
    41. throw new IllegalArgumentException(super.toString());
    42. }
    43. }
    44. }
    45. Affect(row-cnt:1) cost in 537 ms.

    可以看到,动态生成的字节码,跟直接方法调用差别并不是很大。值得注意的是,这个类的classloader是 sun.reflect.DelegatingClassLoader .

    DelegatingClassLoader

    DelegatingClassLoader有何特殊之处?看代码也没有特殊的实现,应该只是为了做classloader隔离。

    1. class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">// sun.reflect.DelegatingClassLoader
    2. // NOTE: this class's name and presence are known to the virtual
    3. // machine as of the fix for 4474172.
    4. class DelegatingClassLoader extends ClassLoader {
    5. DelegatingClassLoader(ClassLoader parent) {
    6. super(parent);
    7. }
    8. }

    之所以搞一个新的类加载器,是为了 性能考虑 ,在某些情况下可以 卸载这些生成的类 ,因为类的卸载是只有在类加载器可以被回收的情况下才会被回收的,如果用了原来的类加载器,那可能导致这些新创建的类一直无法被卸载,从其设计来看本身就不希望他们一直存在内存里的,在需要的时候有就行了,在内存紧俏的时候可以释放掉内存

    • first, it avoids any possible security risk of having these bytecodes in the same loader.

    • Second, it allows the generated bytecodes to be unloaded earlier

      than would otherwise be possible, decreasing run-time footprint.

    1. class="prettyprint hljs gradle" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">// jdk.internal.reflect.ClassDefiner
    2. /** Utility class which assists in calling defineClass() by
    3. creating a new class loader which delegates to the one needed in
    4. order for proper resolution of the given bytecodes to occur. */
    5. class ClassDefiner {
    6. static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
    7. /**

      We define generated code into a new class loader which

    8. delegates to the defining loader of the target class. It is
    9. necessary for the VM to be able to resolve references to the
    10. target class from the generated bytecodes, which could not occur
    11. if the generated code was loaded into the bootstrap class
    12. loader.

    13. There are two primary reasons for creating a new loader

    14. instead of defining these bytecodes directly into the defining
    15. loader of the target class: first, it avoids any possible
    16. security risk of having these bytecodes in the same loader.
    17. Second, it allows the generated bytecodes to be unloaded earlier
    18. than would otherwise be possible, decreasing run-time
    19. footprint.

    20. */
    21. static Class defineClass(String name, byte[] bytes, int off, int len,
    22. final ClassLoader parentClassLoader)
    23. {
    24. ClassLoader newLoader = AccessController.doPrivileged(
    25. new PrivilegedAction() {
    26. public ClassLoader run() {
    27. return new DelegatingClassLoader(parentClassLoader);
    28. }
    29. });
    30. return JLA.defineClass(newLoader, name, bytes, null, "__ClassDefiner__");
    31. }
    32. }

    反射使用过多可能造成的问题

    前面说到达到阈值,切换为动态字节码生成时 没有加锁 。而每次生成动态字节码,都会生成自己的类加载器。如果并发很高,会导致classloader和class过多,占用相应的内存。

     

  • 相关阅读:
    北理工嵩天Python语言程序设计笔记(目录)
    基于深度学习YOLOv8\YOLOv5的花卉识别鲜花识别检测分类系统设计
    UVaLive 6693 Flow Game (计算几何,线段相交)
    PC商城开发
    Rocketmq--消息发送和接收演示
    走出去也是在做研发
    开发前期准备工作
    Day 31 贪心算法 part01 : 理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
    ERROR: No matching distribution found for PIL
    Android 13 - Media框架(8)- MediaExtractor(2)
  • 原文地址:https://blog.csdn.net/Java_ttcd/article/details/126222696