不小心被Cglib忽悠了(已纠正错误2009-3-1)
程序员文章站
2024-01-12 19:42:04
...
最新添加(2009-3-1),纠正文章错误 http://www.iteye.com/topic/336082
原帖
1. 背景 大家都知道,Java的反射调用性能要远低于直接对象调用,一般慢10-20倍多,但很多地方反射调用又是必须的,例如:BeanUtils.copyValues,ORM框架底层等对象映射创建等。因此有的开源框架通过asm等代码生成方式来优化Java反射调用的性能。
cglib中提供了Fast反射功能,包括FastClass,FastMethod等,替代 Java的标准实现,以图提高性能。
2. 问题
但我在实测中发现,cglib的Fast反射框架性能反而不如 JDK的标准反射实现.
测试用例:对ManageLogVO的两个实例进行copyValue,其中第一个是标准方式创建和复制,第二个通过反射方式创建和赋值。
分别采用 Java直接对象操作: testCopyValue();
JDK标准反射调用, testCopyValueUseReflection();
Cglib Fast反射: testCopyValueUseCglib();
执行10000次,尽量模拟真实环境情况。
3. 测试结果
下面是实测结果,记录执行10000次总耗用时间:
testCopyValue 31ms
testCopyValueUseReflection 609ms
testCopyValueUseCglib 922ms
反射耗时是直接操作的20倍,Fast反射更是对象直接操作的30倍。
4 代码片段:
1) 直接操作(共8个属性操作,限于篇幅只列出2个):
2) JDK 反射
3) Cglib Fast反射
通过JProfiler分析,结果类似,并且可以发现 FastClass.getMethod(), FastClass.create(),FastMethod.invoke() 分别是耗时大户,造成性能低下。
5 优化建议:
我的测试用例,基本模拟了真实ORM框架下的一些操作。instance每次创建,method每次都要查找,而由于 getMethod是性能消耗的主要地方,因此,可以考虑对Method做缓存处理,无论对于 JDK反射还是 Cglib fast反射都有一倍以上的性能提高。
引用
真心接受批评,并感谢 sdh5724 指正。
好久没看这个贴了,用 sdh5724 提醒的方式 beanCopier 复制,效率很高,是标准Java反射调用的 1/5.
10000次对象复制测试结果(ms):
task 直接复制 31
task java标准反射复制 610
task cglib Fast复制(不好的写法) 890
task cglib beancopier复制 125
好久没看这个贴了,用 sdh5724 提醒的方式 beanCopier 复制,效率很高,是标准Java反射调用的 1/5.
10000次对象复制测试结果(ms):
task 直接复制 31
task java标准反射复制 610
task cglib Fast复制(不好的写法) 890
task cglib beancopier复制 125
原帖
1. 背景 大家都知道,Java的反射调用性能要远低于直接对象调用,一般慢10-20倍多,但很多地方反射调用又是必须的,例如:BeanUtils.copyValues,ORM框架底层等对象映射创建等。因此有的开源框架通过asm等代码生成方式来优化Java反射调用的性能。
cglib中提供了Fast反射功能,包括FastClass,FastMethod等,替代 Java的标准实现,以图提高性能。
2. 问题
但我在实测中发现,cglib的Fast反射框架性能反而不如 JDK的标准反射实现.
测试用例:对ManageLogVO的两个实例进行copyValue,其中第一个是标准方式创建和复制,第二个通过反射方式创建和赋值。
分别采用 Java直接对象操作: testCopyValue();
JDK标准反射调用, testCopyValueUseReflection();
Cglib Fast反射: testCopyValueUseCglib();
执行10000次,尽量模拟真实环境情况。
3. 测试结果
下面是实测结果,记录执行10000次总耗用时间:
testCopyValue 31ms
testCopyValueUseReflection 609ms
testCopyValueUseCglib 922ms
反射耗时是直接操作的20倍,Fast反射更是对象直接操作的30倍。
4 代码片段:
1) 直接操作(共8个属性操作,限于篇幅只列出2个):
ManagelogVO newVO = new ManagelogVO(); newVO.setLogid(managelogVO.getLogid()); newVO.setOprcode(managelogVO.getOprcode());
2) JDK 反射
Object o = null; try { Class clazz = Class.forName("demo.cglib.ManagelogVO"); o = clazz.newInstance(); Method setterMethod = null; Method getterMethod = null; Object v = null; setterMethod = clazz.getMethod("setLogid", new Class[]{Long.class}); getterMethod = clazz.getMethod("getLogid", null); v = getterMethod.invoke(managelogVO, null); setterMethod.invoke(o, new Object[]{v}); setterMethod = clazz.getMethod("setOprcode", new Class[]{String.class}); getterMethod = clazz.getMethod("getOprcode", null); v = getterMethod.invoke(managelogVO, null); setterMethod.invoke(o, new Object[]{v});
3) Cglib Fast反射
Object o = null; try { Class clazz0 = Class.forName("demo.cglib.ManagelogVO"); // FastClass clazz = FastClass.create(clazz0); o = clazz.newInstance(); FastMethod setterMethod = null; FastMethod getterMethod = null; Object v = null; setterMethod = clazz.getMethod("setLogid", new Class[]{Long.class}); getterMethod = clazz.getMethod("getLogid", null); v = getterMethod.invoke(managelogVO, new Object[]{}); setterMethod.invoke(o, new Object[]{v}); setterMethod = clazz.getMethod("setOprcode", new Class[]{String.class}); getterMethod = clazz.getMethod("getOprcode", null); v = getterMethod.invoke(managelogVO, new Object[]{}); setterMethod.invoke(o, new Object[]{v});
通过JProfiler分析,结果类似,并且可以发现 FastClass.getMethod(), FastClass.create(),FastMethod.invoke() 分别是耗时大户,造成性能低下。
5 优化建议:
我的测试用例,基本模拟了真实ORM框架下的一些操作。instance每次创建,method每次都要查找,而由于 getMethod是性能消耗的主要地方,因此,可以考虑对Method做缓存处理,无论对于 JDK反射还是 Cglib fast反射都有一倍以上的性能提高。
上一篇: 入坑爬虫(八)数据提取之xpath
下一篇: Vuex中的State使用介绍