stone2083

java反射效率

java反射效率到底如何,花了点时间,做了一个简单的测试.供大家参考.

测试背景:
1. 测试简单Bean(int,Integer,String)的set方法
2. loop 1亿次
3. 测试代码尽可能避免对象的创建,复发方法的调用,仅仅测试set方法的耗时

测试结果:
 场景  本机测试结果(XP,双核,2G) 服务器测试结果(Linux,XEN虚拟机,8核,5.5G)
方法直接调用 235MS 190MS
JDK Method调用
29188MS
4633MS
JDK Method调用(稍作优化)
5672MS
4262MS
Cglib FastMethod调用
5390MS
2787MS

得出一个感性的结果:
1.JDK反射效率是直接调用的一个数量级,差不多20倍
2.一个set方法的反射调用时间 = 4633ms / 1亿 / 3次 = 0.0154us
3.Cglib的fastmethod还是有优势的

最后,附上测试代码:
  1 /**
  2  * <pre>
  3  * 本机测试结果(XP,双核,2G):
  4  * 直接调用(LOOP=1亿):       235MS 
  5  * 反射调用(LOOP=1亿):       29188MS
  6  * 反射调用(优化)(LOOP=1亿):  5672MS
  7  * 放射调用(CGLIB)(LOOP=1亿):5390MS
  8  * 
  9  * 服务器测试结果(linux xen虚拟机,5.5G内存;8核CPU):
 10  * 直接调用(LOOP=1亿):       190MS
 11  * 反射调用(LOOP=1亿):       4633MS
 12  * 反射调用(优化)(LOOP=1亿):  4262MS
 13  * 放射调用(CGLIB)(LOOP=1亿):2787MS
 14  * </pre>
 15  * 
 16  * @author Stone.J 2010-9-15 上午10:07:27
 17  */
 18 public class ReflectionTest {
 19 
 20     private static final int                      DEFAULT_INT                = 1;
 21     private static final Integer                  DEFAULT_INTEGER            = 1;
 22     private static final String                   DEFAULT_STRING             = "name";
 23     private static final Object[]                 DEFAULT_INTS               = { 1 };
 24     private static final Object[]                 DEFAULT_INTEGERS           = new Integer[] { 1 };
 25     private static final Object[]                 DEFAULT_STRINGS            = new String[] { "name" };
 26 
 27     private static final Bean                     BEAN                       = new Bean();
 28 
 29     private static final CachedMethod             CACHED_METHOD              = new CachedMethod();
 30     private static final OptimizationCachedMethod OPTIMIZATION_CACHED_METHOD = new OptimizationCachedMethod();
 31     private static final CglibCachedMethod        CGLIB_CACHED_METHOD        = new CglibCachedMethod();
 32 
 33     private static final long                     LOOP                       = 1 * 10000 * 10000;
 34 
 35     // 测试main
 36     public static void main(String[] args) {
 37         if (args.length != 1) {
 38             System.out.println("args error.");
 39             System.exit(1);
 40         }
 41         int tc = Integer.valueOf(args[0]);
 42 
 43         long start = System.currentTimeMillis();
 44         for (long i = 0; i < LOOP; i++) {
 45             switch (tc) {
 46                 case 1:
 47                     // 直接调用
 48                     test();
 49                     break;
 50                 case 2:
 51                     // 反射调用
 52                     testReflection();
 53                     break;
 54                 case 3:
 55                     // 优化后反射调用
 56                     testOptimizationReflection();
 57                     break;
 58                 case 4:
 59                     // cglib反射调用
 60                     testCglibReflection();
 61                     break;
 62                 default:
 63                     System.out.println("tc error. must be [1-4]");
 64                     break;
 65             }
 66         }
 67         long dur = System.currentTimeMillis() - start;
 68         System.out.println(dur);
 69     }
 70 
 71     // 直接调用测试
 72     public static void test() {
 73         BEAN.setId(DEFAULT_INT);
 74         BEAN.setCode(DEFAULT_INTEGER);
 75         BEAN.setName(DEFAULT_STRING);
 76     }
 77 
 78     // 反射调用测试
 79     public static void testReflection() {
 80         try {
 81             CACHED_METHOD.setId.invoke(BEAN, DEFAULT_INTS);
 82             CACHED_METHOD.setCode.invoke(BEAN, DEFAULT_INTEGERS);
 83             CACHED_METHOD.setName.invoke(BEAN, DEFAULT_STRINGS);
 84         } catch (Exception e) {
 85             e.printStackTrace();
 86         }
 87     }
 88 
 89     // 优化后反射调用测试
 90     public static void testOptimizationReflection() {
 91         try {
 92             OPTIMIZATION_CACHED_METHOD.setId.invoke(BEAN, DEFAULT_INTS);
 93             OPTIMIZATION_CACHED_METHOD.setCode.invoke(BEAN, DEFAULT_INTEGERS);
 94             OPTIMIZATION_CACHED_METHOD.setName.invoke(BEAN, DEFAULT_STRINGS);
 95         } catch (Exception e) {
 96             e.printStackTrace();
 97         }
 98     }
 99 
100     // cglib反射调用测试
101     public static void testCglibReflection() {
102         try {
103             CGLIB_CACHED_METHOD.cglibSetId.invoke(BEAN, DEFAULT_INTS);
104             CGLIB_CACHED_METHOD.cglibSetCode.invoke(BEAN, DEFAULT_INTEGERS);
105             CGLIB_CACHED_METHOD.cglibSetName.invoke(BEAN, DEFAULT_STRINGS);
106         } catch (Exception e) {
107             e.printStackTrace();
108         }
109     }
110 
111     /**
112      * <pre>
113      * 测试的bean
114      * 简单的int Integer String类型
115      * </pre>
116      * 
117      * @author Stone.J 2010-9-15 上午10:40:40
118      */
119     public static class Bean {
120 
121         private int     id;
122         private Integer code;
123         private String  name;
124 
125         public int getId() {
126             return id;
127         }
128 
129         public void setId(int id) {
130             this.id = id;
131         }
132 
133         public Integer getCode() {
134             return code;
135         }
136 
137         public void setCode(Integer code) {
138             this.code = code;
139         }
140 
141         public String getName() {
142             return name;
143         }
144 
145         public void setName(String name) {
146             this.name = name;
147         }
148 
149     }
150 
151     /**
152      * 反射测试需要:Cached Method
153      * 
154      * @author Stone.J 2010-9-15 上午10:41:04
155      */
156     public static class CachedMethod {
157 
158         public Method setId;
159         public Method setCode;
160         public Method setName;
161 
162         {
163             try {
164                 setId = Bean.class.getDeclaredMethod("setId"int.class);
165                 setCode = Bean.class.getDeclaredMethod("setCode", Integer.class);
166                 setName = Bean.class.getDeclaredMethod("setName", String.class);
167             } catch (Exception e) {
168                 e.printStackTrace();
169             }
170         }
171 
172     }
173 
174     /**
175      * 反射测试需要:优化后的Cached Method
176      * 
177      * @author Stone.J 2010-9-15 上午10:41:21
178      */
179     public static class OptimizationCachedMethod extends CachedMethod {
180 
181         {
182             /** 所谓的优化 */
183             setId.setAccessible(true);
184             setCode.setAccessible(true);
185             setName.setAccessible(true);
186         }
187 
188     }
189 
190     /**
191      * 反射测试需要,使用cglib的fast method
192      * 
193      * @author Stone.J 2010-9-15 上午10:51:53
194      */
195     public static class CglibCachedMethod extends CachedMethod {
196 
197         public FastMethod cglibSetId;
198         public FastMethod cglibSetCode;
199         public FastMethod cglibSetName;
200 
201         private FastClass cglibBeanClass = FastClass.create(Bean.class);
202 
203         {
204             cglibSetId = cglibBeanClass.getMethod(setId);
205             cglibSetCode = cglibBeanClass.getMethod(setCode);
206             cglibSetName = cglibBeanClass.getMethod(setName);
207         }
208 
209     }
210 
211 }

posted on 2010-09-15 14:04 stone2083 阅读(8004) 评论(9)  编辑  收藏 所属分类: java

Feedback

# re: java反射效率 2010-09-15 17:59 王卫华

如果spring中的bean不使用lazyload并且都是single的,实际上只是启动过程比glib稍慢,运行起来没区别,都是动态生成java类  回复  更多评论   

# re: java反射效率 2010-09-15 20:21 stone2083

@王卫华
你是指spring aop中cglib proxy的实现?  回复  更多评论   

# re: java反射效率 2010-09-16 11:55 Unmi

学到了,

不能什么时候都直接用 set 方法的时候,使用 cglib 的 FastClass 效率还是很可观的啊,Spring、hibernate 等动态框架都用 cglib 的。  回复  更多评论   

# re: java反射效率 2010-09-16 12:57 stone2083

@Unmi
我上面的例子,仅仅是想说明反射调用方法的开销(不局限在get/set上).
如果是对java bean getters/setters的操作,可以考虑使用cglib的BulkBean类.
cglib下的fastclass和fastmethod,确实有一定的优势,但是优先并不明显(在jdk1.6上)  回复  更多评论   

# re: java反射效率[未登录] 2010-09-18 14:54 阿风

Cglib的fastmethod 不错
回去试用下。
谢谢立哥=。=  回复  更多评论   

# re: java反射效率 2011-12-16 11:48 wangwanttt

啥年代了,JDK1.6里的性能用反射跟正常调用差不了多少了,否则SPRING早就垮了  回复  更多评论   

# re: java反射效率 2011-12-16 18:06 stone2083

@wangwanttt
虽然通过JIT做编译优化,但和直接方法调用还是有差距的。
如果你觉得差不多,还请拿出测试数据。谢谢。
  回复  更多评论   

# re: java反射效率 2013-01-24 18:28 大肥牛

@wangwanttt
初始化上反射肯定需要花费更多的时间,spring之所以存在不并不是因为用了反射,而是它本省强大的功能!  回复  更多评论   

# re: java反射效率 2013-02-07 11:08 WeiPeng

测试貌似没有预热,如果事先预热一下,反射调用和直接调用差距可能更小。  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: