当前位置:网站首页>Is reflection really time-consuming? How long does it take to reflect 100000 times.
Is reflection really time-consuming? How long does it take to reflect 100000 times.
2022-06-11 12:06:00 【Q.E.D.】
Whether in the interview process , Or look at various technical articles on the Internet , Just mention reflection , Inevitably, a problem will be mentioned , Does reflection affect performance ? What is the impact ? If you are writing business code , You used reflection , Will be review People send out soul torture , Why use reflection , Is there any other solution .
The answer is the same online , For example, slow reflection 、 Frequent object creation during reflection takes up more memory 、 Frequent triggers GC wait . So how slow is the reflection ? How much memory does reflection take up ? establish 1 Create an object or create 10 How long does it take for 10000 objects ? Single reflection or 10 How long does it take for 10000 reflections ? There is no intuitive concept in our mind , And today's article will tell you .
This article , Designed several common scenes , Let's discuss whether reflection is really time-consuming ? Finally, it will be shown in the form of charts .
1、 Test tools and schemes
Before we start, we need to define a reflection class Person.
class Person {
var age = 10
fun getName(): String {
return "I am DHL"
}
companion object {
fun getAddress(): String = "BJ"
}
}For the above test class , The following common scenarios are designed , Verify the time before and after reflection .
- Create objects
- Method call
- Calling a
- Companion
1.1、 Testing tools and codes
JMH (Java Microbenchmark Harness), This is a Oracle A benchmark tool developed , They know better than anyone JIT as well as JVM The impact of optimization on the testing process , Therefore, using this tool can ensure the reliability of the results as much as possible .
Benchmarking is a way to test application performance , Test the performance index of an object under specific conditions .
1.2、 Why use JMH
because JVM Will do all kinds of code optimization , If you just print a timestamp before and after the code , The result of such calculation is unbelievable , Because it ignores JVM In the process of execution , The impact of optimizing code . and JMH It will minimize the impact of these optimizations on the final results .
1.3、 Test plan
- In single process 、 Single thread , For the above four scenarios , Each scenario tested five rounds , Each cycle 10 Ten thousand times , Calculate their average .
- Before execution , You need to warm up the code , Preheating will not be the end result , The purpose of preheating is to construct a relatively stable environment , Ensure the reliability of the results . because JVM Code that executes frequently , Try to compile to machine code , So as to improve the execution speed . Preheating involves not only compiling into machine code , Also contains JVM Various optimization algorithms , Try to reduce JVM The optimization of the , Construct a relatively stable environment , Reduce the impact on the results .
- JMH Provide Blackhole, adopt Blackhole Of consume To avoid JIT The optimization .
1.4、Kotlin and Java The reflection mechanism of
All the test code in this article uses Kotlin,Koltin Is perfectly compatible Java Of , So you can also use Java The reflection mechanism of , however Kotlin I also encapsulated a set of reflection mechanism , Not to replace Java Of , yes Java Enhanced Edition , because Kotlin It has its own grammatical features, such as extension methods 、 Companion 、 Check of nullable type, etc , If you want to use Kotlin The reflex mechanism , The following libraries need to be introduced .
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"At the beginning of the analysis , We need to compare Java Get to know Kotlin Reflection basic grammar .
kotlin Of KClass Corresponding Java Of Class, We can do it in the following ways KClass and Class Mutual transformation between
// obtain Class
Person().javaClass
Person()::class.java
Person::class.java
Class.forName("com.hi-dhl.demo.Person")
// obtain KClass
Person().javaClass.kotlin
Person::class
Class.forName("com.hi-dhl.demo.Person").kotlinkotlin Of KProperty Corresponding Java Of Field,Java Of Field Yes getter/setter Method , But in Kotlin There is no Field, Divided into KProperty and KMutableProperty, When the variable is used val When making a statement , That is, the attribute is KProperty, If the variable is var When making a statement , That is, the attribute is KMutableProperty.
// Java How to get
Person().javaClass.getDeclaredField("age")
// Koltin How to get
Person::class.declaredMemberProperties.find { it.name == "age" }stay Kotlin in function 、 attribute as well as Constructors The supertypes of are KCallable, The corresponding subtype is KFunction ( function 、 Construction method, etc ) and KProperty / KMutableProperty ( attribute ), and Kotlin Medium KCallable Corresponding Java Of AccessibleObject, Its sub types are Method 、 Field 、 Constructor.
// Java
Person().javaClass.getConstructor().newInstance() // Construction method
Person().javaClass.getDeclaredMethod("getName") // Member method
// Kotlin
Person::class.primaryConstructor?.call() // Construction method
Person::class.declaredFunctions.find { it.name == "getName" } // Member method Whether to use Java still Kotlin The final test results are the same , After understanding the basic reflection grammar , We test the time consumption of the above four scenes before and after reflection .
2、 Create objects
2.1、 Create objects normally
@Benchmark
fun createInstance(bh: Blackhole) {
for (index in 0 until 100_000) {
bh.consume(Person())
}
}The average time taken for five rounds of testing 0.578 ms/op . We need to pay more attention to , It's used here JMH Provide Blackhole, adopt Blackhole Of consume() Ways to avoid JIT The optimization , Make the results closer to reality .
During object creation , Will first check whether the class has been loaded , If the class is already loaded , Space will be allocated directly to the object , One of the most time-consuming stages is actually the class loading process ( load -> verification -> Get ready -> analysis -> initialization ).
2.2、 Create objects by reflection
@Benchmark
fun createReflectInstance(bh: Blackhole) {
for (index in 0 until 100_000) {
bh.consume(Person::class.primaryConstructor?.call())
}
}The average time taken for five rounds of testing 4.710 ms/op, Objects are created normally 9.4 times , The result is amazing , If the intermediate operation ( Get construction method ) Extract from the loop , So what happens .
2.3、 Reflection optimization
@Benchmark
fun createReflectInstanceAccessibleTrue(bh: Blackhole) {
val constructor = Person::class.primaryConstructor
for (index in 0 until 100_000) {
bh.consume(constructor?.call())
}
}As you can see , I'll do the middle operation ( Get construction method ) Extract from the loop , The average time taken for five rounds of testing 1.018 ms/op, The speed has been greatly improved , Compared with the speed before reflection optimization 4.7 times , But what if we're turning off the security check function .
constructor?.isAccessible = trueisAccessible It is used to judge whether safety inspection is required , Set to true Means to turn off the security check , It will reduce the time-consuming of safety inspection , The average time taken for five rounds of testing 0.943 ms/op, The reflection speed is further improved .
The final results of several rounds of tests are shown below .

3、 Method call
3.1、 Normal call
@Benchmark
fun callMethod(bh: Blackhole) {
val person = Person()
for (index in 0 until 100_000) {
bh.consume(person.getName())
}
}
The average time taken for five rounds of testing 0.422 ms/op.
3.2、 Reflection call
@Benchmark
fun callReflectMethod(bh: Blackhole) {
val person = Person()
for (index in 0 until 100_000) {
val method = Person::class.declaredFunctions.find { it.name == "getName" }
bh.consume(method?.call(person))
}
}
The average time taken for five rounds of testing 10.533 ms/op, It is called normally 26 times . If we take the intermediate operation ( obtain getName Code ) Extract from the loop , What will happen .
3.3、 Reflection optimization
@Benchmark
fun callReflectMethodAccessiblFalse(bh: Blackhole) {
val person = Person()
val method = Person::class.declaredFunctions.find { it.name == "getName" }
for (index in 0 until 100_000) {
bh.consume(method?.call(person))
}
}
The intermediate operation ( obtain getName Code ) Extracted from the loop , The average time taken for five rounds of testing 0.844 ms/op, The speed has been greatly improved , Compared with the speed before reflection optimization 13 times , What if you're turning off the security check .
method?.isAccessible = true
The average time taken for five rounds of testing 0.687 ms/op, The reflection speed is further improved .
The final results of several rounds of tests are shown below .

4、 Calling a
4.1、 Normal call
@Benchmark
fun callPropertie(bh: Blackhole) {
val person = Person()
for (index in 0 until 100_000) {
bh.consume(person.age)
}
}
The average time taken for five rounds of testing 0.241 ms/op .
4.2、 Reflection call
@Benchmark
fun callReflectPropertie(bh: Blackhole) {
val person = Person()
for (index in 0 until 100_000) {
val propertie = Person::class.declaredMemberProperties.find { it.name == "age" }
bh.consume(propertie?.call(person))
}
}
The average time taken for five rounds of testing 12.432 ms/op, It is called normally 62 times , Then we'll do the middle operation ( Get the code of the property ) Out of the loop .
4.3、 Reflection optimization
@Benchmark
fun callReflectPropertieAccessibleFalse(bh: Blackhole) {
val person = Person::class.createInstance()
val propertie = Person::class.declaredMemberProperties.find { it.name == "age" }
for (index in 0 until 100_000) {
bh.consume(propertie?.call(person))
}
}
The intermediate operation ( Get the code of the property ) After being lifted out of the loop , The average time taken for five rounds of testing 1.362 ms/op, The speed has been greatly improved , Compared with the speed before reflection optimization 8 times , We're turning off the security check , Take a look at the results .
propertie?.isAccessible = true
The average time taken for five rounds of testing 1.202 ms/op, The reflection speed is further improved .
The final results of several rounds of tests are shown below .

5、 Companion
5.1、 Normal call
@Benchmark
fun callCompaion(bh: Blackhole) {
for (index in 0 until 100_000) {
bh.consume(Person.getAddress())
}
}
The average time taken for five rounds of testing 0.470 ms/op .
5.2、 Reflection call
@Benchmark
fun createReflectCompaion(bh: Blackhole) {
val classes = Person::class
val personInstance = classes.companionObjectInstance
val personObject = classes.companionObject
for (index in 0 until 100_000) {
val compaion = personObject?.declaredFunctions?.find { it.name == "getAddress" }
bh.consume(compaion?.call(personInstance))
}
}
The average time taken for five rounds of testing 5.661 ms/op, It is called normally 11 times , Then let's take a look at the middle operation ( obtain getAddress Code ) The result from the loop .
5.3、 Reflection optimization
@Benchmark
fun callReflectCompaionAccessibleFalse(bh: Blackhole) {
val classes = Person::class
val personInstance = classes.companionObjectInstance
val personObject = classes.companionObject
val compaion = personObject?.declaredFunctions?.find { it.name == "getAddress" }
for (index in 0 until 100_000) {
bh.consume(compaion?.call(personInstance))
}
}
The intermediate operation ( obtain getAddress Code ) Out of the loop , The average time taken for five rounds of testing 0.840 ms/op, The speed has been greatly improved , Compared with the speed before reflection optimization 7 times , Now we're turning off the security check .
compaion?.isAccessible = true
The average time taken for five rounds of testing 0.702 ms/op, The reflection speed is further improved .
The final results of several rounds of tests are shown in the figure below .

6、 summary
We compared four common scenarios : Create objects 、 Method call 、 Calling a 、 Companion . The time consumption before and after reflection was tested respectively , Finally, summarize the five rounds 10 Average of 10000 tests ( Table slidable ).

The time consumption before and after reflection of each scene is shown in the figure below .

In our impression , Reflection is the devil , The impact will be very big , But from the table above , Reflection does have an effect , But if we use reflection properly , The optimized reflection result is not as big as expected , Here are some suggestions .
1. In scenes where reflection is frequently used , Extract the reflection intermediate operation and cache it , The next time you use reflection, just get it directly from the cache .
2. Turn off the security check , Can further improve performance .
Finally, let's look at the time-consuming of creating objects with a single shot and creating objects with a single reflection , As shown in the figure below .

Score Show the result ,Error Indicates the error range , Considering the error , Their time-consuming gap is Don't be subtle .
Of course, depending on the equipment ( High end machine 、 Low end machine ), And the system 、 Complex classes and other factors , The effects of reflection are also different . Reflection is widely used in practical projects , A lot of design and development is about reflection , For example, calling bytecode files through reflection 、 Call the system to hide Api、 Design pattern of dynamic agent ,Android reverse 、 The famous Spring frame 、 Various types Hook Frame, etc .
This is the end of the article , If it helps you , welcome Looking at 、 give the thumbs-up 、 Collection 、 Share To my friends .
边栏推荐
猜你喜欢

JS addition and multiplication error resolution number precision

JEST 单元测试说明 config.json

. The way to prove the effect of throwing exceptions on performance in. Net core

C# 设置或验证 PDF中的文本域格式

PS does not display text cursor, text box, and does not highlight after selection

Splunk Bucket 背後的秘密

ELK - Hearthbeat实现服务监控

Wechat web developers, how to learn web development

Specflow环境搭建
![[JUC supplementary] atomic class, unsafe](/img/24/e51cfed39fe820fb46cca548af1782.jpg)
[JUC supplementary] atomic class, unsafe
随机推荐
Using fast and slow pointer method to solve the problem of array (C language)
Live app development to determine whether the user is logging in to the platform for the first time
Read geo expression matrix
(解决)Splunk 之 kv-store down 问题
The wonderful use of XOR (C language)
中国网络安全年会周鸿祎发言:360安全大脑构筑数据安全体系
[JUC supplementary] atomic class, unsafe
Elk - x-pack set user password
PS does not display text cursor, text box, and does not highlight after selection
Iframe value transfer
Elk - elastalert largest pit
2020-07 学习笔记整理
C # apply many different fonts in PDF documents
01_ Description object_ Class diagram
Intl.numberformat set number format
Pan domain SSL certificate, sectigo cheap wildcard certificate popularization plan
POJ 3278 catch the cow (width first search, queue implementation)
带你了解直接插入排序(C语言)
Uncaught TypeError: Cannot set property ‘next‘ of undefined 报错解决
Eulato