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 閱讀(8030) 評論(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

          測試貌似沒有預熱,如果事先預熱一下,反射調用和直接調用差距可能更小。  回復  更多評論   

          主站蜘蛛池模板: 义乌市| 綦江县| 镇平县| 虞城县| 五大连池市| 大厂| 杭州市| 海伦市| 襄汾县| 葫芦岛市| 朝阳市| 屏边| 莫力| 衡东县| 延寿县| 米泉市| 施秉县| 和林格尔县| 奉贤区| 银川市| 泸溪县| 邢台市| 岑溪市| 于田县| 含山县| 镇平县| 仁怀市| 嘉峪关市| 博野县| 靖江市| 莆田市| 上栗县| 连江县| 滨州市| 茌平县| 巴林右旗| 淄博市| 肇东市| 方山县| 丘北县| 岐山县|