浏览 9110 次
锁定老帖子 主题:cglib相关性能测试对比
精华帖 (1) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-11-03
背景:
继上一篇文章 cglib源码学习交流 很多同学提出,因中文文档缺乏,导致对文章中的介绍看的不是很明白,更多的只是想了解具体的使用即可。所以趁势写了这篇博文,主要是将cglib中的几个工具类和常用的Reflect ,BeanUtils做一个对比,顺便也介绍一下cglib的相关用法,一举两得,望大家多多支持。
正题:1. 首先定义一份Pojo Bean ,后续的测试主要围绕这个进行。
public static class CopyBean { private int intValue; private boolean boolValue; private float floatValue; private double doubleValue; private long longValue; private char charValue; private byte byteValue; private short shortValue; private Integer integerValue; private Boolean boolObjValue; private Float floatObjValue; private Double doubleObjValue; private Long longObjValue; private Short shortObjValue; private Byte byteObjValue; private BigInteger bigIntegerValue; private BigDecimal bigDecimalValue; private String stringValue; ......// 一堆的setter/getter方法 }
说明: 该copyBean基本包含了java的所有原型对象,基本对象,和常用的BigDecimal,BigInteger,总共17个属性。
2. 定义测试模板 (模板模式)
定义一个TestCallback接口。
interface TestCallback { String getName(); CglibPerformanceTest.CopyBean call(CglibPerformanceTest.CopyBean source); }
定义测试的模板方法 private static final DecimalFormat integerFormat = new DecimalFormat("#,###"); public static void testTemplate(TestCallback callback, CopyBean source, int count) { int warmup = 10; // 先进行预热,加载一些类,避免影响测试 for (int i = 0; i < warmup; i++) { callback.call(source); } restoreJvm(); // 进行GC回收 // 进行测试 long start = System.nanoTime(); for (int i = 0; i < count; i++) { callback.call(source); } long nscost = (System.nanoTime() - start); System.out.println(callback.getName() + " total cost=" + integerFormat.format(nscost) + "ns , each cost=" + nscost / count + "ns"); restoreJvm();// 进行GC回收 }
说明:
restoreJvm相关方法: private static void restoreJvm() {
int maxRestoreJvmLoops = 10; long memUsedPrev = memoryUsed(); for (int i = 0; i < maxRestoreJvmLoops; i++) { System.runFinalization(); System.gc(); long memUsedNow = memoryUsed(); // 如果多次GC后内存稳定了,就退出 if ((ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount() == 0) && (memUsedNow >= memUsedPrev)) { break; } else { memUsedPrev = memUsedNow; } } } private static long memoryUsed() { Runtime rt = Runtime.getRuntime(); return rt.totalMemory() - rt.freeMemory(); }
3. 准备原始的CopyBean数据
private static CopyBean getBean() { CopyBean bean = new CopyBean(); bean.setIntValue(1); bean.setBoolValue(false); bean.setFloatValue(1.0f); bean.setDoubleValue(1.0d); bean.setLongValue(1l); bean.setCharValue('a'); bean.setShortValue((short) 1); bean.setByteValue((byte) 1); bean.setIntegerValue(new Integer("1")); bean.setBoolObjValue(new Boolean("false")); bean.setFloatObjValue(new Float("1.0")); bean.setDoubleObjValue(new Double("1.0")); bean.setLongObjValue(new Long("1")); bean.setShortObjValue(new Short("1")); bean.setByteObjValue(new Byte("1")); bean.setBigIntegerValue(new BigInteger("1")); bean.setBigDecimalValue(new BigDecimal("1")); bean.setStringValue("1"); return bean; }
4. 执行相关测试测试环境说明:
第一测试主要是一个对象的全部属性进行拷贝
1. BeanCopier (cglib)
2. PropertyUtils (apache-common)
3. BeanUtils (apache-common)
测试结果:
测试次数:testCount = 1000 * 1000 = 100万次
从这个结果可以看出, BeanCopier是PropertyUtils的504倍, PropertyUtils是BeanUtils的1.71倍, BeanCopier是PropertyUtils的861.84倍,差了近3个数量级。
第二测试主要是一个对象的单个属性进行拷贝
1. BulkBean
// 测试BulkBean final BulkBean bulkBean = BulkBean.create(bean.getClass(), new String[] { getMethodName }, new String[] { setMethodName }, new Class[] { Integer.class }); final CopyBean bulkBeanTarget = new CopyBean(); testTemplate(new TestCallback() { @Override public String getName() { return "BulkBean"; } @Override public CopyBean call(CopyBean source) { Object[] result = bulkBean.getPropertyValues(source); // 先调用getter bulkBean.setPropertyValues(bulkBeanTarget, result); // 再调用setter return bulkBeanTarget; } }, bean, testCount); 2. BeanMap
// 测试BeanMap final BeanMap sourceMap = BeanMap.create(bean); // 预先创建对象 final BeanMap targetMap = BeanMap.create(new CopyBean()); final CopyBean beanMapTarget = new CopyBean(); testTemplate(new TestCallback() { @Override public String getName() { return "BeanMap"; } @Override public CopyBean call(CopyBean source) { targetMap.setBean(beanMapTarget); // 将目标对象设置于beanMap Object obj = sourceMap.get(fieldName); targetMap.put(fieldName, obj); return beanMapTarget; } }, bean, testCount); 3. FastClass/FastMethod
// 测试FastClass final FastClass fastClass = FastClass.create(bean.getClass()); final FastMethod setFastMetod = fastClass.getMethod(setMethodName, new Class[] { Integer.class }); final FastMethod getFastMetod = fastClass.getMethod(getMethodName, new Class[] {}); final CopyBean fastClassTarget = new CopyBean(); testTemplate(new TestCallback() { @Override public String getName() { return "FastClass"; } @Override public CopyBean call(CopyBean source) { try { Object field = getFastMetod.invoke(source, new Object[] {});// 调用get方法 setFastMetod.invoke(fastClassTarget, new Object[] { field });// 调用set方法赋值 } catch (Exception e) { e.printStackTrace(); } return fastClassTarget; } }, bean, testCount); 4. 未处理的jdk reflect
try { // 进行method对象cache,真实应用中一般都会cache method对象 final Method getMethod = bean.getClass().getMethod(getMethodName, new Class[] {}); final Method setMethod = bean.getClass().getMethod(setMethodName, new Class[] { Integer.class }); // 测试未优化过的Reflect final CopyBean reflect1Target = new CopyBean(); testTemplate(new TestCallback() { @Override public String getName() { return "未优化过的Reflect"; } @Override public CopyBean call(CopyBean source) { try { Object field = getMethod.invoke(source, new Object[] {}); setMethod.invoke(reflect1Target, new Object[] { field }); } catch (Exception e) { e.printStackTrace(); } return reflect1Target; } }, bean, testCount); } catch (Exception e1) { e1.printStackTrace(); } } 5. 处理过的jdk reflect
try { // 进行method对象cache,真实应用中一般都会cache method对象 final Method getMethod = bean.getClass().getMethod(getMethodName, new Class[] {}); final Method setMethod = bean.getClass().getMethod(setMethodName, new Class[] { Integer.class }); // 测试优化过的Reflect getMethod.setAccessible(true);// 设置不进行access权限检查 setMethod.setAccessible(true);// 设置不进行access权限检查 final CopyBean reflect2Target = new CopyBean(); testTemplate(new TestCallback() { @Override public String getName() { return "优化过的Reflect"; } @Override public CopyBean call(CopyBean source) { try { Object field = getMethod.invoke(source, new Object[] {}); setMethod.invoke(reflect2Target, new Object[] { field }); } catch (Exception e) { e.printStackTrace(); } return reflect2Target; } }, bean, testCount); } catch (Exception e1) { e1.printStackTrace(); }
测试结果:
测试次数:testCount = 1000 * 1000 * 100 = 1亿次
测试结果,性能相差不多,差距不大,这也可以说明jdk对reflect调用的优化已经做的很棒了。
最后测试数据仅拱参考,最后测试代码可见附件。测试方法如存在问题,欢迎拍砖
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-11-05
LZ用的应该是SUN的JVM吧.建议测试下JRockit下的性能.
|
|
返回顶楼 | |
发表时间:2010-11-05
J9的性能如何?
|
|
返回顶楼 | |
发表时间:2010-11-09
ouchxp 写道 LZ用的应该是SUN的JVM吧.建议测试下JRockit下的性能.
恩,用的是jdk 1.6.18,下次可以我装一下JRockit, openjdk测试做一个比较。 针对cglib beanCopier和BeanUtils的性能查了接近860多倍,有点让我诧异 原先在自己笔记本双核2G内存跑了,只查了10倍左右,没想到上了服务器,配置了一下jvm参数,性能差距就这么明显 看来以后做测试还得尽量找一下服务器跑跑, |
|
返回顶楼 | |
发表时间:2011-03-17
看不懂哇……
|
|
返回顶楼 | |
发表时间:2011-03-17
ganjp 写道 看不懂哇…… http://rednaxelafx.iteye.com/blog/548536 |
|
返回顶楼 | |