"In-depth understanding of Java virtual machine" How does JVM implement reflection?

1. Implementation of reflection call

local implementation

package com.sz.simple;

import java.lang.reflect.Method;

public class Test {
    public static void target() {
        new Exception("#").printStackTrace();
    }

    public static void main(String[] args) throws Exception {

        Test test = new Test();

        Class<?> klass = Class.forName("com.sz.simple.Test");
        Method method = klass.getMethod("target");
        method.invoke(test,null);
    }
}

As shown in the above code, when the main method is executed, the bytecode object of the class is first obtained through the fully qualified class name, and then the method object is obtained and then the target method is called and executed reflectively. The stack trace when the print method is executed is shown in the figure below

image-20230512141230970

The reflection class calls the invoke method of the delegated class, then the delegated class calls the invoke method of the local method, and finally executes the target method

Java reflection method -> java delegation method -> c++ local method -> java target method

Since the process from java to c++ method and then to java method is very time-consuming, in addition to delegating to local method implementations, delegating classes can also delegate to dynamic method implementations

Dynamic implementation

Modify the above code to look like this

package com.sz.simple;

import java.lang.reflect.Method;

public class Test {
    public static void target(int i) {
        new Exception("#"+i).printStackTrace();
    }

    public static void main(String[] args) throws Exception {

        Test test = new Test();

        Class<?> klass = Class.forName("com.sz.simple.Test");

        for (int i = 0; i < 17; i++) {
            Method method = klass.getMethod("target",int.class);
            method.invoke(test,i);
        }

    }
}
java -verbose:class com.sz.simple.Test

image-20230512142314822

Comparing the 15th and 16th prints, you will find that during the 16th execution, the delegation class is delegated to GeneratedMethodAccessor, which adopts dynamic implementation.

We can modify the value of Dsun.reflect.inflationThreshold by modifying the value of 15 dynamically implemented. If your project uses reflection to call methods extensively, and you don’t want to generate a large number of dynamically generated classes, you can set Dsun.reflect.inflationThreshold = int.max

If you don't want to use the local implementation to call the target method, you can add the following parameters when executing

-Dsun.reflect.noInflation=true

2. Implementation efficiency of two reflection calls

Dynamic implementation is 20 times faster than local implementation [2]. This is because the dynamic implementation does not need to switch from Java to C++ and then to Java, but because the generation of bytecode is very time-consuming, if it is called only once, the local implementation is 3 to 4 times faster [3].

Guess you like

Origin blog.csdn.net/JAVAlife2021/article/details/130642063