cglib相关性能测试对比

背景: 

 

继上一篇文章 cglib源码学习交流 

很多同学提出,因中文文档缺乏,导致对文章中的介绍看的不是很明白,更多的只是想了解具体的使用即可。所以趁势写了这篇博文,主要是将cglib中的几个工具类和常用的Reflect ,BeanUtils做一个对比,顺便也介绍一下cglib的相关用法,一举两得,望大家多多支持。

 

正题:

1.  首先定义一份Pojo Bean ,后续的测试主要围绕这个进行。

1.public static class CopyBean {
2.
3.        private int        intValue;
4.        private boolean    boolValue;
5.        private float      floatValue;
6.        private double     doubleValue;
7.        private long       longValue;
8.        private char       charValue;
9.        private byte       byteValue;
10.        private short      shortValue;
11.        private Integer    integerValue;
12.        private Boolean    boolObjValue;
13.        private Float      floatObjValue;
14.        private Double     doubleObjValue;
15.        private Long       longObjValue;
16.        private Short      shortObjValue;
17.        private Byte       byteObjValue;
18.        private BigInteger bigIntegerValue;
19.        private BigDecimal bigDecimalValue;
20.        private String     stringValue;
21.......// 一堆的setter/getter方法
22.}

 说明: 该copyBean基本包含了java的所有原型对象,基本对象,和常用的BigDecimal,BigInteger,总共17个属性。

 

2.  定义测试模板 (模板模式)

 

   定义一个TestCallback接口。

1.interface TestCallback {
2.
3.    String getName();
4.
5.    CglibPerformanceTest.CopyBean call(CglibPerformanceTest.CopyBean source);
6.}

 定义测试的模板方法 

   private static final DecimalFormat integerFormat = new DecimalFormat("#,###");

1.public static void testTemplate(TestCallback callback, CopyBean source, int count) {
2.        int warmup = 10;
3.        // 先进行预热,加载一些类,避免影响测试
4.        for (int i = 0; i < warmup; i++) {
5.            callback.call(source);
6.        }
7.        restoreJvm(); // 进行GC回收
8.        // 进行测试
9.        long start = System.nanoTime();
10.        for (int i = 0; i < count; i++) {
11.            callback.call(source);
12.        }
13.        long nscost = (System.nanoTime() - start);
14.        System.out.println(callback.getName() + " total cost=" + integerFormat.format(nscost) + "ns , each cost="
15.                           + nscost / count  + "ns");
16.        restoreJvm();// 进行GC回收
17.
18.    }

 说明:

 

  • 为了测试更加精确,避免因为在一次的循环中进行处理,jvm内存,GC,Class装载对测试的影响,有一个warmup的过程,先执行少量的测试方法,这里是执行10次
  • 避免jvm内存GC对测试id影响,这里有restoreJvm强制进行一次jvm GC

 restoreJvm相关方法:

   private static void restoreJvm() {

1.    int maxRestoreJvmLoops = 10;
2.    long memUsedPrev = memoryUsed();
3.    for (int i = 0; i < maxRestoreJvmLoops; i++) {
4.        System.runFinalization();
5.        System.gc();
6.
7.        long memUsedNow = memoryUsed();
8.        //  如果多次GC后内存稳定了,就退出
9.        if ((ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount() == 0)
10.            && (memUsedNow >= memUsedPrev)) {
11.            break;
12.        } else {
13.            memUsedPrev = memUsedNow;
14.        }
15.    }
16.}
17.
18.private static long memoryUsed() {
19.    Runtime rt = Runtime.getRuntime();
20.    return rt.totalMemory() - rt.freeMemory();
21.}

3.  准备原始的CopyBean数据

1.private static CopyBean getBean() {
2.        CopyBean bean = new CopyBean();
3.        bean.setIntValue(1);
4.        bean.setBoolValue(false);
5.        bean.setFloatValue(1.0f);
6.        bean.setDoubleValue(1.0d);
7.        bean.setLongValue(1l);
8.        bean.setCharValue('a');
9.        bean.setShortValue((short) 1);
10.        bean.setByteValue((byte) 1);
11.        bean.setIntegerValue(new Integer("1"));
12.        bean.setBoolObjValue(new Boolean("false"));
13.        bean.setFloatObjValue(new Float("1.0"));
14.        bean.setDoubleObjValue(new Double("1.0"));
15.        bean.setLongObjValue(new Long("1"));
16.        bean.setShortObjValue(new Short("1"));
17.        bean.setByteObjValue(new Byte("1"));
18.        bean.setBigIntegerValue(new BigInteger("1"));
19.        bean.setBigDecimalValue(new BigDecimal("1"));
20.        bean.setStringValue("1");
21.        return bean;
22.    }

4. 执行相关测试

测试环境说明:

 

  • 操作系统 Linux ccbu-156-49 2.6.18-131.el5.customxen #1 SMP Tue Sep 15 15:46:11 CST 2009 x86_64 x86_64 x86_64 GNU/Linux
  • 虚拟8cpu , 5G内存
  • jdk  1.6.0_18
  • jvm 参数 
  • 1.-server -Xmx2g -Xms2g -Xmn512m -XX:PermSize=196m -Xss256k -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70  

第一测试主要是一个对象的全部属性进行拷贝

  • BeanCopier  (cglib)
  • PropertyUtils (apache-common)
  • BeanUtils (apache-common)

1.  BeanCopier  (cglib)

1.// beanCopier测试
2.     final BeanCopier beanCopier = BeanCopier.create(CopyBean.class, CopyBean.class, false);
3.        final CopyBean beanCopierTarget = new CopyBean();//new一次,避免new对象产生的代价影响测试结果
4.        testTemplate(new TestCallback() {
5.
6.            public String getName() {
7.                return "BeanCopier";
8.            }
9.
10.            public CopyBean call(CopyBean source) {
11.                beanCopier.copy(source, beanCopierTarget, null);
12.                return beanCopierTarget;
13.            }
14.        }, bean, testCount);

2. PropertyUtils (apache-common) 

1.<span style="background-color: rgba(0, 0, 0, 0);">// PropertyUtils测试
2.        final CopyBean propertyUtilsTarget = new CopyBean();
3.        testTemplate(new TestCallback() {
4.
5.            public String getName() {
6.                return "PropertyUtils";
7.            }
8.
9.            public CopyBean call(CopyBean source) {
10.                try {
11.                    PropertyUtils.copyProperties(propertyUtilsTarget, source);
12.                } catch (Exception e) {
13.                    e.printStackTrace();
14.                }
15.                return propertyUtilsTarget;
16.            }
17.
18.        }, bean, testCount);</span>

3. BeanUtils (apache-common)

  • 1.<span style="background-color: rgba(0, 0, 0, 0);">// BeanUtils测试
    2.        final CopyBean beanUtilsTarget = new CopyBean();
    3.        testTemplate(new TestCallback() {
    4.
    5.            public String getName() {
    6.                return "BeanUtils";
    7.            }
    8.
    9.            public CopyBean call(CopyBean source) {
    10.                try {
    11.                    BeanUtils.copyProperties(beanUtilsTarget, source);
    12.                } catch (Exception e) {
    13.                    e.printStackTrace();
    14.                }
    15.                return beanUtilsTarget;
    16.            }
    17.
    18.        }, bean, testCount);</span>
    

测试结果: 

 

测试次数:testCount = 1000 * 1000 = 100万次

  • BeanCopier total cost=36,626,000ns , each cost=36ns
  • PropertyUtils total cost=18,173,767,000ns , each cost=18173ns
  • BeanUtils total cost=31,236,079,000ns , each cost=31236ns

从这个结果可以看出, BeanCopier是PropertyUtils的504倍, PropertyUtils是BeanUtils的1.71倍, BeanCopier是PropertyUtils的861.84倍,差了近3个数量级。

第二测试主要是一个对象的单个属性进行拷贝 

  • BulkBean (cglib)
  • BeanMap (cglib)
  • FastClass/FastMethod  (cglib)
  • 未处理的jdk reflect (jdk)
  • 处理的jdk reflect (jdk)

1. BulkBean 

1.// 测试BulkBean
2.        final BulkBean bulkBean = BulkBean.create(bean.getClass(), new String[] { getMethodName },
3.                                                  new String[] { setMethodName }, new Class[] { Integer.class });
4.        final CopyBean bulkBeanTarget = new CopyBean();
5.        testTemplate(new TestCallback() {
6.
7.            @Override
8.            public String getName() {
9.                return "BulkBean";
10.            }
11.
12.            @Override
13.            public CopyBean call(CopyBean source) {
14.                Object[] result = bulkBean.getPropertyValues(source); // 先调用getter
15.                bulkBean.setPropertyValues(bulkBeanTarget, result); // 再调用setter
16.                return bulkBeanTarget;
17.            }
18.
19.        }, bean, testCount);

2. BeanMap


1.// 测试BeanMap
2.        final BeanMap sourceMap = BeanMap.create(bean); // 预先创建对象
3.        final BeanMap targetMap = BeanMap.create(new CopyBean());
4.        final CopyBean beanMapTarget = new CopyBean();
5.        testTemplate(new TestCallback() {
6.
7.            @Override
8.            public String getName() {
9.                return "BeanMap";
10.            }
11.
12.            @Override
13.            public CopyBean call(CopyBean source) {
14.                targetMap.setBean(beanMapTarget); // 将目标对象设置于beanMap
15.                Object obj = sourceMap.get(fieldName);
16.                targetMap.put(fieldName, obj);
17.                return beanMapTarget;
18.            }
19.
20.        }, bean, testCount);

 3. FastClass/FastMethod

1.// 测试FastClass
2.        final FastClass fastClass = FastClass.create(bean.getClass());
3.        final FastMethod setFastMetod = fastClass.getMethod(setMethodName, new Class[] { Integer.class });
4.        final FastMethod getFastMetod = fastClass.getMethod(getMethodName, new Class[] {});
5.        final CopyBean fastClassTarget = new CopyBean();
6.        testTemplate(new TestCallback() {
7.
8.            @Override
9.            public String getName() {
10.                return "FastClass";
11.            }
12.
13.            @Override
14.            public CopyBean call(CopyBean source) {
15.
16.                try {
17.                    Object field = getFastMetod.invoke(source, new Object[] {});// 调用get方法
18.                    setFastMetod.invoke(fastClassTarget, new Object[] { field });// 调用set方法赋值
19.                } catch (Exception e) {
20.                    e.printStackTrace();
21.                }
22.
23.                return fastClassTarget;
24.            }
25.
26.        }, bean, testCount);

4.  未处理的jdk reflect

1.try {
2.            // 进行method对象cache,真实应用中一般都会cache method对象
3.            final Method getMethod = bean.getClass().getMethod(getMethodName, new Class[] {});
4.            final Method setMethod = bean.getClass().getMethod(setMethodName, new Class[] { Integer.class });
5.            // 测试未优化过的Reflect
6.            final CopyBean reflect1Target = new CopyBean();
7.            testTemplate(new TestCallback() {
8.
9.                @Override
10.                public String getName() {
11.                    return "未优化过的Reflect";
12.                }
13.
14.                @Override
15.                public CopyBean call(CopyBean source) {
16.                    try {
17.                        Object field = getMethod.invoke(source, new Object[] {});
18.                        setMethod.invoke(reflect1Target, new Object[] { field });
19.                    } catch (Exception e) {
20.                        e.printStackTrace();
21.                    }
22.                    return reflect1Target;
23.                }
24.
25.            }, bean, testCount);
26.
27.        } catch (Exception e1) {
28.            e1.printStackTrace();
29.        }
30.
31.    }

5. 处理过的jdk reflect

1.try {
2.            // 进行method对象cache,真实应用中一般都会cache method对象
3.            final Method getMethod = bean.getClass().getMethod(getMethodName, new Class[] {});
4.            final Method setMethod = bean.getClass().getMethod(setMethodName, new Class[] { Integer.class });
5.            // 测试优化过的Reflect
6.            getMethod.setAccessible(true);// 设置不进行access权限检查
7.            setMethod.setAccessible(true);// 设置不进行access权限检查
8.            final CopyBean reflect2Target = new CopyBean();
9.            testTemplate(new TestCallback() {
10.
11.                @Override
12.                public String getName() {
13.                    return "优化过的Reflect";
14.                }
15.
16.                @Override
17.                public CopyBean call(CopyBean source) {
18.                    try {
19.                        Object field = getMethod.invoke(source, new Object[] {});
20.                        setMethod.invoke(reflect2Target, new Object[] { field });
21.                    } catch (Exception e) {
22.                        e.printStackTrace();
23.                    }
24.                    return reflect2Target;
25.                }
26.
27.            }, bean, testCount);
28.        } catch (Exception e1) {
29.            e1.printStackTrace();
30.        }

测试结果:  

 

测试次数:testCount = 1000 * 1000 * 100 = 1亿次

  • BulkBean total cost=2,125,759,000ns , each cost=21ns
  • BeanMap total cost=2,730,912,000ns , each cost=27ns
  • FastClass total cost=2,576,470,000ns , each cost=25ns
  • 未处理过的Reflect total cost=2,882,755,000ns , each cost=28ns
  • 处理过的Reflect total cost=2,792,828,000ns , each cost=27ns

测试结果,性能相差不多,差距不大,这也可以说明jdk对reflect调用的优化已经做的很棒了。

最后

测试数据仅拱参考,最后测试代码可见附件。测试方法如存在问题,欢迎拍砖

时间: 2025-01-07 11:21:13

cglib相关性能测试对比的相关文章

Deepgreen与Greenplum TPC-H性能测试对比(使用VitesseData脚本)

前两天发了一篇基于[德哥测试脚本]的测试对比文章<Deepgreen与Greenplum TPC-H性能测试对比(使用德哥脚本)>,由于测试数据量少,两个数据库有几轮测试都是1秒持平,但是大多数测试Deepgreen均优于Greenplum,有的甚至快至百倍,感兴趣的朋友可以再回头看看. 今天分享一下Deepgreen提供的TPC-H测试脚本,这个脚本分为浮点类型.数值类型两类进行22轮测试,更加细化,并且结果值更加中肯. 一.测试环境 服务器 IP 节点 Master 192.168.100

几种序列化协议(protobuf,xstream,jackjson,jdk,hessian)相关数据对比

最近研究了下google protobuf协议,顺便对比了一下json,xml,java序列化相关的数据对比,从几个纬度进行对比.   别人的相关测试数据: http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking   测试纬度 序列化时间 反序列化时间 bytes大小 测试代码 准备protobuf文件 1.import "InnerMessage.proto"; 2.package demo; 3.opti

Deepgreen与Greenplum TPC-H性能测试对比(使用德哥脚本)

Deepgreen数据库基于开源MPP数据库Greenplum而来,那么他的优越性几何?今天给大家分享数据仓库测试TPC-H的结果让大家加以比较: 本次对比需要注意的几点: 测试参照德哥2015年发的[Greenplum的TPC-H]测试,只做了压缩类型的简单修改 由于测试机器性能问题,可能无法最大化展示二者性能(greenplum部分测试timeout) 一.测试环境: 服务器 IP 节点 Master 192.168.100.107 1 Master Segment1 192.168.100

Windows Server 2008 R2和SP2性能测试对比

之所以去安装SP1,是因为我的电脑有16G内存,虽然安装的是Windows 7 x64版本,但是每当内存使用超过了4G,鼠标反应就会很迟钝,很卡.尤其是在同时运行FLASH PRO 和 PHOTOSHOP . ECLIPSE的时候. 很郁闷,所以想安装SP1试试效果,测试结果虽然有了一点提升,但是问题依旧. 该卡还是卡,内存使用不能超过4G,超过就卡,完全浪费了我16G内存的配置.于是昨天晚上挨个尝试了WINDOWS 2008 R2 和 WINDOWS 2008 SP2. 经过测试,最终选择了

ArrayList和LinkedList的几种循环遍历方式及性能对比分析

主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayList和LinkedList的源码实现分析性能结果,总结结论. 通过本文你可以了解(1)List的五种遍历方式及各自性能 (2)foreach及Iterator的实现 (3)加深对ArrayList和LinkedList实现的了解. 阅读本文前希望你已经了解ArrayList顺序存储和LinkedList链式的结构,本文不对此进行介绍. 相关:HashMap循环遍历方式及其性

如何组建性能测试团队?

问题描述: 如何组建性能测试团队? 精彩答案: 会员 fatfish: 随着软件应用的越来越广泛,软件产品的规模和使用群体正在呈爆发式增长,因此性能测试越来越受到软件供应商的重视,此外在某些领域中,对应用软件的性能表现有着显著的依赖和要求,如军工.通信.金融.商超等等,这些行业的应用软件往往会因为一些性能方面的表现不达标导致项目失败或给用户带来灾难性的损失!所以性能测试逐渐成为了软件质量保障的一个重要组成部分,而相应的,如何组建一个高效的性能测试团队自然就成为了有效进行性能测试的关键. 由于历史

HashMap循环遍历方式及其性能对比

主要介绍HashMap的四种循环遍历方式,各种方式的性能测试对比,根据HashMap的源码实现分析性能结果,总结结论. 1. Map的四种遍历方式 下面只是简单介绍各种遍历示例(以HashMap为例),各自优劣会在本文后面进行分析给出结论. (1) for each map.entrySet() Java 1 2 3 4 5 Map<String, String> map = new HashMap<String, String>(); for (Entry<String,

性能测试在软件企业的应用

随着软件行业的不断发展,越来越多的企业更加重视产品的质量.性能测试已经成为软件质量保障的一个重要因素.一个软件性能的优劣很有可能直接决定一个软件的成败,甚至一个企业的兴衰.每个软件企业都有各自不同的应用领域,有着不同的实际情况,这样必然要求每个企业量体裁衣,选择适合自己的应用策略. 大型企业.大型项目的应用策略 大型企业应用的软件系统,业务比较复杂.用户数很多.存在并发情况.业务的响应时间.操作的实时性.稳定性.安全性.可恢复性等都要求很高. 象银行.电信.铁路等大型企业一般通过CMMI. IS

SSD硬盘性能测试比较

由于公司最近需要上SSD,用于MySQL数据库服务器,以下针对单块480G SSD.接RAID卡240G SSD* 2 RAID0,以及与普通硬盘SATA硬盘以及SAS(raid10)做个比较: 480G SSD: INTEL SSDSC2BP480G4 SATA:WD6401AALS-00J7B1 240*2 SSD RAID0:  INTEL SSDSC2BP240410BTJR408108F5240AGN    RAID卡: LSI MegaRAID SAS 9271-4i 300G*4