反射机制性能测试

背景

  目前项目中用到了反射,但是java反射机制会造成一定的性能损失,需要初步确定其造成的损失程度。这次测试场景较为粗糙,有待进一步详细测试。

测试场景

硬件设备

  • 电脑型号:MacBook Pro

  • 系统版本:macOS High Sierra 10.13.1

  • 处理器:2.7 GHz Intel Core i5

  • 内存:8G

  • jvm版本:1.8.0_144

  • 堆最大内存:2G

方法调用机制

对比以下三种调用机制执行同一操作相同次数的耗时

  • 直接调用
  • Java反射,这里先反射需要调用的方法,只记录方法执行耗时
  • ReflectAsm反射

待执行方法

  • 简单方法,get一个int行变量
  • 稍复杂方法,add两个long型变量

测试用例

待反射类定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class InvokeClass {


private int a = 1;

public int getA() {
return a;
}

public long add(long a, long b) {
return a + b;
}

}

反射执行get方法

执行次数:Integer.MAX_VALUE,即(2^31 - 1)次

直接调用

1
2
3
4
5
6
7
InvokeClass invokeClass = new InvokeClass();
long start = System.currentTimeMillis();
for (int i = 0; i < Integer.MAX_VALUE; i++) {
invokeClass.getA();
}
long end = System.currentTimeMillis();
System.out.println(end - start);

平均耗时5ms

Java反射

1
2
3
4
5
6
7
8
Method method = InvokeClass.class.getMethod("getA");
set.setAccessible(true); //此处很重要,不设置的话每次反射会去判断方法是否能访问,造成性能损失,大约耗时5000ms
long start = System.currentTimeMillis();
for (int i = 0; i < Integer.MAX_VALUE; i++) {
method.invoke(invokeClass);
}
long end = System.currentTimeMillis();
System.out.println(end - start);

平均耗时3000ms

ReflectAsm反射

1
2
3
4
5
6
7
8
9

MethodAccess methodAccess = MethodAccess.get(InvokeClass.class);
int index = methodAccess.getIndex("getA");
long start = System.currentTimeMillis();
for (int i = 0; i < Integer.MAX_VALUE; i++) {
methodAccess.invoke(invokeClass, index);
}
long end = System.currentTimeMillis();
System.out.println(end - start);

平均耗时30ms

反射执行Add方法

直接调用

1
2
3
4
5
6
7
InvokeClass invokeClass = new InvokeClass();
long start = System.currentTimeMillis();
for (long i = 0; i < Integer.MAX_VALUE; i++) {
invokeClass.add(i, i);
}
long end = System.currentTimeMillis();
System.out.println(end - start);

平均耗时1000ms

java反射

1
2
3
4
5
6
7
8
9

Method method = InvokeClass.class.getMethod("add", long.class, long.class);
set.setAccessible(true);
long start = System.currentTimeMillis();
for (long i = 0; i < Integer.MAX_VALUE; i++) {
method.invoke(invokeClass, i, i);
}
long end = System.currentTimeMillis();
System.out.println(end - start);

平均耗时18000ms

ReflectAsm反射

1
2
3
4
5
6
7
8
MethodAccess methodAccess = MethodAccess.get(InvokeClass.class);
int index = methodAccess.getIndex("add", long.class, long.class);
long start = System.currentTimeMillis();
for (long i = 0; i < Integer.MAX_VALUE; i++) {
methodAccess.invoke(invokeClass, index, i, i);
}
long end = System.currentTimeMillis();
System.out.println(end - start);

平均耗时2700ms

对比及结论

直接调用 Java反射 ReflectASM反射
get方法 5 3000 30
add方法 1000 18000 2700

经过简单测试,可以发现

  1. 反射确实会带来性能损失,ReflectAsm相比Java原生反射机制能提升一定性能
  2. 待反射方法的复杂程度会对反射耗时带来一定影响,需要进一步详细测试
-------------本文结束感谢您的阅读-------------

本文标题:反射机制性能测试

文章作者:小建儿

发布时间:2018年03月23日 - 17:03

最后更新:2018年11月17日 - 18:11

原始链接:http://yajian.github.io/反射机制性能测试/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。