Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is Java reflection and performance

2025-01-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article focuses on "what is Java reflection and performance". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "what is Java reflection and performance"?

Catalogue

I. preparation

Second, reflection call process

1. Use of reflection

The difference between 2.getMethod and getDeclaredMethod

3. Call reflection method

Fourth, the reasons for the low reflection efficiency

Fifth, reflection optimization

I. preparation

Note: this case is for JDK1.8

Test the code:

[TestRef.java] public class TestRef {public static void main (String [] args) {try {Class clazz = Class.forName ("com.allen.commons.entity.CommonTestEntity"); Object refTest = clazz.newInstance (); Method method = clazz.getMethod ("defaultMethod"); / / Method method1 = clazz.getDeclaredMethod ("defaultMethod"); method.invoke (refTest) } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {e.printStackTrace () }}-[CommonTestEntity.java] public class CommonTestEntity {static {System.out.println ( "CommonTestEntity performs class loading.") } public CommonTestEntity () {System.out.println (this.getClass () + "| CommonTestEntity instance initialization |" + this.getClass (). GetClassLoader ());} public void defaultMethod () {System.out.println ("execute instance method: defaultMethod");}} II. Reflection call flow 1. Use of reflection

1) create a class object (class load, load using the ClassLoader of the class where the current method is located)

2) get Method objects (getMethod and getDeclaredMethod)

3) call the invoke method

The difference between 2.getMethod and getDeclaredMethod

The getMethod source code is as follows:

Public Method getMethod (String name, Class... ParameterTypes) throws NoSuchMethodException, SecurityException {Objects.requireNonNull (name); SecurityManager sm = System.getSecurityManager (); if (sm! = null) {/ / 1. Check method permissions checkMemberAccess (sm, Member.PUBLIC, Reflection.getCallerClass (), true);} / / 2. Get method Method method = getMethod0 (name, parameterTypes); if (method = = null) {throw new NoSuchMethodException (methodToString (name, parameterTypes));} / / 3. Returns the method return method;}-public Method getDeclaredMethod (String name, Class...) ParameterTypes) throws NoSuchMethodException, SecurityException {Objects.requireNonNull (name); SecurityManager sm = System.getSecurityManager (); if (sm! = null) {/ / 1. The check method is permission checkMemberAccess (sm, Member.DECLARED, Reflection.getCallerClass (), true);} / / 2. Get method Method method = searchMethods (privateGetDeclaredMethods (false), name, parameterTypes); if (method = = null) {throw new NoSuchMethodException (methodToString (name, parameterTypes));} / / 3. Return method return method;}

The process of getting the method is divided into three steps:

a. Check method permissions

b. Get method Method object

c. Return method

There are two main differences:

In 1.getMethod, checkMemberAccess passes in Member.PUBLIC, while getDeclaredMethod passes in Member.DECLARED.

Comments in the code:

The difference between PUBLIC and DECLARED is explained in the comment. PUBLIC will include all public methods, including parent methods, while DECLARED will include all self-defined methods. Public,protected,private is here, but not parent methods.

In 2.getMethod, it is getMethod0 that gets the method call, while getDeclaredMethod gets the method call privateGetDeclaredMethods. PrivateGetDeclaredMethods is a method that gets the definition of the class itself, and the parameter is boolean publicOnly, indicating whether only public methods are obtained.

The privateGetDeclaredMethods source code is as follows:

/ / Returns an array of "root" methods. These Method objects must NOT / / be propagated to the outside world, but must instead be copied / / via ReflectionFactory.copyMethod. Private Method [] privateGetDeclaredMethods (boolean publicOnly) {checkInitted (); Method [] res; ReflectionData rd = reflectionData (); if (rd! = null) {res = publicOnly? Rd.declaredPublicMethods: rd.declaredMethods; if (res! = null) return res;} / / No cached value available; request value from VM res = Reflection.filterMethods (this, getDeclaredMethods0 (publicOnly)); if (rd! = null) {if (publicOnly) {rd.declaredPublicMethods = res;} else {rd.declaredMethods = res }} return res;}

① relectionData is obtained through cache

② if the cache misses, get the method through getDeclaredMethods0

The getMethod0 source code is as follows:

Private Method getMethod0 (String name, Class [] parameterTypes, boolean includeStaticMethods) {MethodArray interfaceCandidates = new MethodArray (2); Method res = privateGetMethodRecursive (name, parameterTypes, includeStaticMethods, interfaceCandidates); if (res! = null) return res; / / Not found on class or superclass directly interfaceCandidates.removeLessSpecifics (); return interfaceCandidates.getFirst (); / / may be null}

The privateGetDeclaredMethods method and searchMethods method are also called in the privateGetMethodRecursive method.

3.getMethod method flow

4.getDeclaredMethod method flow

3. Call reflection method

Invoke source code:

Class Method {public Object invoke (Object obj, Object...) Args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {if (! override) {Class caller = Reflection.getCallerClass (); / / 1. Check permissions checkAccess (caller, clazz, Modifier.isStatic (modifiers)? Null: obj.getClass (), modifiers);} / / 2. Get MethodAccessor MethodAccessor ma = methodAccessor; / / read volatile if (ma = = null) {/ / create MethodAccessor ma = acquireMethodAccessor ();} / / 3. Call MethodAccessor.invoke return ma.invoke (obj, args);}}

Method.invoke () is not really self-implemented reflection calling logic, but rather delegated to sun.reflect.MethodAccessor to handle it.

Each actual Java method has only one corresponding Method object as a root (essentially a member variable of the Method class). Each time a Method object is obtained through reflection, a new Method object is created to encapsulate the root. Before calling the invoke () method of an actual Java method corresponding to the Method object for the first time, the MethodAccessor object that implements the calling logic is created and updated to root on the first call, and then calls MethodAccessor.invoke () to actually complete the reflection call.

MethodAccessor is only a single method interface, and its invoke () method corresponds to Method.invoke (). It is ReflectionFactory that creates the MethodAccessor instance.

There are two versions of the MethodAccessor implementation, one implemented by Java and the other implemented by native code.

The MethodAccessorImpl call efficiency of the Java version is more than 20 times faster than that of the Native version, but the Java version consumes 3-4 times more resources than the Native version when loading, so the Native version is called by default. If the number of calls exceeds 15 times, the more efficient Java version will be selected.

Threshold in Native version (static constant)

Fourth, the reasons for the low reflection efficiency

The 1.Method#invoke method encapsulates and unencapsulates the parameters.

We can see that the parameter of the invoke method is of type Object [], that is, if the method parameter is a simple type (basic data type in 8), it needs to be converted to an Object type here, such as long. When javac compile uses the Long.valueOf () transformation, there is a large number of Object that generates Long, and the parameter passed in is the Object [] value, which requires additional encapsulation of the object array.

As we can see in the above MethodAccessorGenerator#emitInvoke method, when the bytecode is generated, the parameter array will be taken apart, the parameters will be restored to what they were before they were wrapped by Object [], and the parameters will also be verified. Here, unpacking operation is involved.

Therefore, when reflecting calls, there is additional unnecessary memory waste because of encapsulation and unencapsulation, and when the number of calls reaches a certain amount, it will also lead to GC.

two。 Need to check method visibility

CheckAccess method

3. Need to traverse the method and verify the parameters

SearhMethod in PrivateGetMethodRecursive

4.JIT cannot be optimized

It is mentioned in JavaDoc that:

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

Fifth, reflection optimization

1. (see online) try not to getMethods () and then traverse the filter, but directly use getMethod (methodName) to get the method based on the method name.

But when getting the method in the source code, in the searchMethods method, it also uses the way of traversing all the methods. However, the number of methods traversed by getMethod,getDeclaredMethod is relatively small because it does not include methods of the parent class.

two。 Cache class object

A) Class.forName performance is relatively poor

B) as mentioned above, when getting a specific method, the native method is called each time to get the method list and traverse the list to determine the input parameter type and return type. Caching the reflected method/field/constructor object will greatly improve performance.

3. Involving dynamic proxies: in practical use, the performance of CGLIB and Javassist proxy implementation based on dynamic code is better than that of JDK's own dynamic proxy.

The dynamic proxy included in JDK is a dynamic proxy based on the interface, and its performance is much higher than the direct reflection operation, because the metadata related to the interface instance is created in the static code block and has been cached in the class member attribute, so it is called directly during the run time, and there is no additional reflection overhead.

4. Using ReflectASM to speed up reflection by generating bytecode (difficult to use)

At this point, I believe you have a deeper understanding of "what is Java reflection and performance". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report