反照性能到底会差多少
在网上曾看到关于MVC框架的性能比较,根据他们的测试,struts1,springMVC,struts2其性能是从高到低,struts2的性能表现是最差的,到底什么原因使struts2在性能表现上如此差强人意,依照友友们的观点主要有以下原因:
1、拦截器的大量使用
2、valueStack的维护
3、OGNL表达式的使用
网上都有相应的解决方案,感兴趣的友友们可以去搜索看看。因为上面列出的三点影响struts2性能的观点,都用了大量的反射,所以我想在这里讨论下反射的性能。好了,费话不多说了,进入主题。
一,定义一个类如下,此类是为了测试创建对象和调用方法使用
class T { int x, y, z, a, b, c, d, e, f, g, h, i, j, k; long aa, bb, cc, dd, ee, ff, gg, hh, ii, jj, kk, xx, yy, zz, ll, mm; T tt, ttt, tttt, ttttt, ttttttt, tttttttt; public void sayHello() { x = 9; } }
二、下面是测试类
package com.xuch.memory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { int max = 1000; for (int m = 0; m < 6; m++) { long st = System.currentTimeMillis(); Class clazz = Class.forName("com.xuch.memory.T"); (1) for (int i = 0; i < max; i++) { (反射) Object o = clazz.newInstance(); Method me = clazz.getMethod("sayHello"); (reflect method invoke ) me.invoke(o); } long et = System.currentTimeMillis(); long start = System.currentTimeMillis(); for (int i = 0; i < max; i++) { (正常) T t = new T(); t.sayHello(); (normal method invoke) } long end = System.currentTimeMillis(); long normal = end - start; long reflect = et - st; double rate = 0; if(normal != 0) { rate = (double)reflect /(double) normal ; } System.out.println("以下打印信息是根据不同测试方式会做不同的调整"); System.out.println("----------------------------------------------"); System.out.println("创建对象,并进行方法调用,正常和反射间的比较"); System.out.println("只用了一次Class.forName()加载类"); System.out.println(" 此次循环的次数为:" + max); System.out.println(" 正常方式创建对象,并进行方法调用所用时间的毫秒数:"+normal); System.out.println(" 反射方式方式创建对象,并进行方法调用所用时间的毫秒数:"+reflect); System.out.println(" 反射/正常为:"+rate); System.out.println("----------------------------------------------"); System.out.println(); max*=10; } } }
上面是完整的代码,下面贴下我的测试结果:
1、分别用正常和反射方式创建对象,也就是说代码中标注“正常”和“反射”的FOR循环中都不包括方法的调用,只有对象创建的代码,并且class.forName()方法在for的外边。下面是测试结果:
只用了一次Class.forName()加载类
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前先调用了Class.forName()加载类
此次循环的次数为:1000
正常方式创建对象所用时间的毫秒数:0
反射方式方式创建对象所用时间的毫秒数:5
反射/正常为:0.0
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前先调用了Class.forName()加载类
此次循环的次数为:10000
正常方式创建对象所用时间的毫秒数:0
反射方式方式创建对象所用时间的毫秒数:15
反射/正常为:0.0
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前先调用了Class.forName()加载类
此次循环的次数为:100000
正常方式创建对象所用时间的毫秒数:20
反射方式方式创建对象所用时间的毫秒数:85
反射/正常为:4.25
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前先调用了Class.forName()加载类
此次循环的次数为:1000000
正常方式创建对象所用时间的毫秒数:165
反射方式方式创建对象所用时间的毫秒数:825
反射/正常为:5.0
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前先调用了Class.forName()加载类
此次循环的次数为:10000000
正常方式创建对象所用时间的毫秒数:1655
反射方式方式创建对象所用时间的毫秒数:8221
反射/正常为:4.967371601208459
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前先调用了Class.forName()加载类
此次循环的次数为:100000000
正常方式创建对象所用时间的毫秒数:16497
反射方式方式创建对象所用时间的毫秒数:82296
反射/正常为:4.988543371522095
----------------------------------------------
2、其它条件和1一样,这次只不过把Class.forName()方法放在了for的里面
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前每次都先调用了Class.forName()加载类
此次循环的次数为:1000
正常方式创建对象所用时间的毫秒数:0
反射方式方式创建对象所用时间的毫秒数:10
反射/正常为:0.0
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前每次都先调用了Class.forName()加载类
此次循环的次数为:10000
正常方式创建对象所用时间的毫秒数:5
反射方式方式创建对象所用时间的毫秒数:30
反射/正常为:6.0
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前每次都先调用了Class.forName()加载类
此次循环的次数为:100000
正常方式创建对象所用时间的毫秒数:20
反射方式方式创建对象所用时间的毫秒数:260
反射/正常为:13.0
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前每次都先调用了Class.forName()加载类
此次循环的次数为:1000000
正常方式创建对象所用时间的毫秒数:165
反射方式方式创建对象所用时间的毫秒数:2570
反射/正常为:15.575757575757576
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前每次都先调用了Class.forName()加载类
此次循环的次数为:10000000
正常方式创建对象所用时间的毫秒数:1655
反射方式方式创建对象所用时间的毫秒数:25606
反射/正常为:15.47190332326284
----------------------------------------------
----------------------------------------------
创建对象,正常和反射间的比较
在使用反射前每次都先调用了Class.forName()加载类
此次循环的次数为:100000000
正常方式创建对象所用时间的毫秒数:16545
反射方式方式创建对象所用时间的毫秒数:256077
反射/正常为:15.477606527651858
----------------------------------------------
3、创建对象,并进行方法调用,正常和反射间的比较,这次的测试就如贴上的代码的真实测试,包括创建对象,并进行方法调用。
----------------------------------------------
创建对象,并进行方法调用,正常和反射间的比较
只用了一次Class.forName()加载类
此次循环的次数为:1000
正常方式创建对象,并进行方法调用所用时间的毫秒数:0
反射方式方式创建对象,并进行方法调用所用时间的毫秒数:15
反射/正常为:0.0
----------------------------------------------
----------------------------------------------
创建对象,并进行方法调用,正常和反射间的比较
只用了一次Class.forName()加载类
此次循环的次数为:10000
正常方式创建对象,并进行方法调用所用时间的毫秒数:5
反射方式方式创建对象,并进行方法调用所用时间的毫秒数:45
反射/正常为:9.0
----------------------------------------------
----------------------------------------------
创建对象,并进行方法调用,正常和反射间的比较
只用了一次Class.forName()加载类
此次循环的次数为:100000
正常方式创建对象,并进行方法调用所用时间的毫秒数:20
反射方式方式创建对象,并进行方法调用所用时间的毫秒数:340
反射/正常为:17.0
----------------------------------------------
----------------------------------------------
创建对象,并进行方法调用,正常和反射间的比较
只用了一次Class.forName()加载类
此次循环的次数为:1000000
正常方式创建对象,并进行方法调用所用时间的毫秒数:165
反射方式方式创建对象,并进行方法调用所用时间的毫秒数:3310
反射/正常为:20.060606060606062
----------------------------------------------
----------------------------------------------
创建对象,并进行方法调用,正常和反射间的比较
只用了一次Class.forName()加载类
此次循环的次数为:10000000
正常方式创建对象,并进行方法调用所用时间的毫秒数:1665
反射方式方式创建对象,并进行方法调用所用时间的毫秒数:32856
反射/正常为:19.733333333333334
----------------------------------------------
----------------------------------------------
创建对象,并进行方法调用,正常和反射间的比较
只用了一次Class.forName()加载类
此次循环的次数为:100000000
正常方式创建对象,并进行方法调用所用时间的毫秒数:16690
反射方式方式创建对象,并进行方法调用所用时间的毫秒数:328532
反射/正常为:19.684361893349312
----------------------------------------------
结论:
一,如果只是创建对象,反射所有的时间是正常的5倍(反射创建对象时并不是每次都去加载类)
二,如果只是创建对象,每次反射创建对象时都去加载类,反射所用的时间是正常的15倍(这说明Class.forName是很费时间的)
三,如果创建对象,并调用方法(因为方法里基本上没有做什么操作,这里只是看调用方法这个动作对性能的影响),反射所有的时间是正常的20倍(反射创建对象时并不是每次都去加载类)。
而且用正常方式,只要循环次数相同,其所用时间也基本上在同一数量级。这说明使用反射调用方法要花费很长时间来准备
反射虽然提供了方便,灵活,但其是以性能为代价的