当前位置:网站首页>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 .
边栏推荐
- Read geo expression matrix
- Use cache to reduce network requests
- Four ways to create threads
- Memory mapping image of the grayloc module in the surfacefinder process
- mysql 导入宝塔中数据库data为0000-00-00,enum为null出错
- Generate statement is not synthesized
- Splunk 健康检查之关闭THP
- Addition of large numbers (C language)
- Software project management 7.1 Basic concept of project schedule
- 软件项目管理 7.1.项目进度基本概念
猜你喜欢

Uncaught typeerror: cannot set property 'next' of undefined

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

中文输入法输入事件composition的使用

Intl.numberformat set number format

ELK - Hearthbeat实现服务监控

Hang up the interviewer

flask 框架web开发视频笔记

Zhejiang University and Microsoft Asia Research Institute released a new method of video recognition, which can recognize video frame by frame without data marking, or can be used for sign language tr

C # set or verify the format of text field in PDF
Use cache to reduce network requests
随机推荐
浙大联合微软亚研院发布视频识别新方法,可对视频逐帧识别且无需,数据标记,或可用于手语翻译等
Zhouhongyi's speech at the China Network Security Annual Conference: 360 secure brain builds a data security system
大数相加(C语言)
The wonderful use of XOR (C language)
yapi安装
Splunk Bucket 背後的秘密
Splunk健康检查orphaned searches
01_ Description object_ Class diagram
Where is it safer to open an account for soda ash futures? How much capital is needed for a transaction?
C # apply many different fonts in PDF documents
C# 将OFD转为PDF
Splunk 最佳实践-减轻captain 负担
(解决)Splunk 之 kv-store down 问题
Android 11+ 配置SqlServer2014+
中国联通 22春招 群面
Sulley fuzzer learning
Generate statement is not synthesized
C# 设置或验证 PDF中的文本域格式
Adjust the array order so that odd numbers precede even numbers (C language)
Specflow环境搭建