代码:
public static void test() {
int i = 0;
}
public static void main(String[] args)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
int times = Integer.MAX_VALUE;
Method method = ReflectTest.class.getMethod("test", null);
long start = System.currentTimeMillis();
while (times-->0) {
method.invoke(ReflectTest.class);
}
long end1 = System.currentTimeMillis();
while (++times<Integer.MAX_VALUE) {
test();
}
long end2 = System.currentTimeMillis();
System.out.println("end1 - start: " + (end1-start)+", end2 - end1: "+(end2-end1));
}
结果:end1 - start: 9137, end2 - end1: 1 查了千倍,Method 方法已经算是缓存,而且不在计时之内。计时只是 invoke 方法,差异这么大,有办法改善吗?
1
leavic 2019-06-26 15:03:50 +08:00
不好意思误入了,我以为你在讨论 RF 的反射。。。
|
4
cjlmwcy 2019-06-26 15:15:19 +08:00
实际操作的时候可以把方法缓存起来,会好一些
|
6
gz911122 2019-06-26 15:16:47 +08:00
有
比如 apt,编译期间生成代码 再比如 aspectj 等字节码织入的 |
7
guyeu 2019-06-26 16:35:05 +08:00
```java
method.setAccessible(true); ``` 可以比你现有代码的反射提升一倍的效率,再要提升效率,就木有办法了。。。其实反射和方法调用的性能差距已经在微秒级了,很多场合可以忽略这种差距。 |
8
lingnin 2019-06-26 17:18:48 +08:00
别用 java
|
9
firefffffffffly 2019-06-26 17:40:08 +08:00
性能有差距,但是应该不会像例子里这么大, 这段代码做 benchmark 不太严谨,比如第二段代码可能会被 jit 优化到没有。
依照这个测试 https://dzone.com/articles/the-performance-cost-of-reflection 不包含具体逻辑的情况下测试大约是差 10 倍。 |
10
luozic 2019-06-26 17:47:41 +08:00 via iPhone
缓存
|
11
mind3x 2019-06-26 17:56:03 +08:00 14
2.6GHz 主频的 7 代 i5,MIPS(每秒执行百万条指令数)大约是 53K。
0 循环到 max int,循环次数是 2,147,483,647,假设每个循环只执行三条指令,大约是 6K 个百万条指令。 也就是说,一个什么也不做的从 0 到 max int 的循环,在 7 代 i5 上,大约应该花 0.1 秒这么个量级的时间。我们就放宽一点,给它再快个 10 倍,大约应该花 10ms 这个量级的时间。今天应该还没有一款 CPU 的单核 IPC 能达到 10 倍 i5 的水平。 你猜猜看你的第二个循环为啥 1ms 就跑完了? 因为 JIT 在跑了前面的几百或者几千次循环以后开始介入编译,发现你的 test()很小,应该内联进循环,然后就内联了。内联以后一看原来整个循环也啥也没做,就把循环也优化掉了。 而第一个循环,反射是实打实没法优化掉的。 这个故事告诉我们,microbenchmark 通常没什么鸟用。如果一定要做 microbenchmark,请至少正确使用 JMH,在代码里通过 JMH 的 API 强制添加副作用,避免不希望的优化发生。 另外,即使反射比普通调用真的慢一千倍,实际到你的产品里很可能也只有不到 1%的差距。打个比方,如果你的方法本身要花 1 秒,反射花 1 毫秒,直接调用花 1 微秒,把你的方法调用 1 万次,区别也只有千分之一。 |
12
MotherShip 2019-06-26 18:05:43 +08:00
@mind3x 讲的很详细。。我有点想提醒楼主 JIT 的优化但是讲不出所以然来
|
13
guixiexiezou 2019-06-26 18:10:11 +08:00
楼上说的很清楚了。差距是有,但不会这么大,大概是 47 倍到 147 之间
|
14
wdlth 2019-06-26 23:14:53 +08:00
试试 ReflectASM
|
15
troywinter 2019-06-27 20:55:47 +08:00
#11 楼正解,java 的 microbenchmark 很重要,做跑分一定要有足够的预热,不然你测出来的结果是比 python 还慢,然而真实情况并不是这样,microbenchmark 是 java 开发者的基础。
|
16
crazyweeds 2021-05-13 22:04:13 +08:00
@mind3x 活捉一头大佬
|