当前位置:网站首页>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 .
边栏推荐
- Merge two ordered arrays (C language)
- Software project management 7.1 Basic concept of project schedule
- [第二章 基因和染色体的关系]生物知识概括–高一生物
- Use of Chinese input method input event composition
- When I saw the sudden death of a 28 year old employee, I wanted to moisten
- Splunk 最佳实践-减轻captain 负担
- Wechat web developers, how to learn web development
- arguments.callee 实现函数递归调用
- Splunk Bucket 背後的秘密
- The wonderful use of XOR (C language)
猜你喜欢

Let you understand bubble sorting (C language)

让你理解选择排序(C语言)

Generate statement is not synthesized

JS addition and multiplication error resolution number precision

刷题笔记(十三)--二叉树:前中后序遍历(复习)

mysql 导入宝塔中数据库data为0000-00-00,enum为null出错

浙大联合微软亚研院发布视频识别新方法,可对视频逐帧识别且无需,数据标记,或可用于手语翻译等

Use of Chinese input method input event composition

【LeetCode】1049. Weight of the last stone II (wrong question 2)

. The way to prove the effect of throwing exceptions on performance in. Net core
随机推荐
[digital signal processing] correlation function (property of correlation function | maximum value of correlation function | maximum value of autocorrelation function | maximum value of cross correlat
P2580 "so he started the wrong roll call"
.net core 抛异常对性能影响的求证之路
安全工程师发现PS主机重大漏洞 用光盘能在系统中执行任意代码
Eulato
gocron 定时任务管理平台
Dominating set, independent set, covering set
C# 在PDF文档中应用多种不同字体
The role of Gerber file in PCB manufacturing
Elk - hearthbeat implements service monitoring
arguments. Callee implement function recursive call
什么是Gerber文件?PCB电路板Gerber文件简介
Weekly Postgres world news 2022w08
《公司理财师专业能力》笔记
InputStream read file OutputStream create file
How does Sister Feng change to ice?
Typescript compilation options and configuration files
JVM优化
创建线程的四种方式
Intl.numberformat set number format