設(shè)計java

          j2ee輕量級框架,IMVC,IORM && web網(wǎng)絡(luò)游戲

          java反射性能測試分析

              java有別于其他編程語言而讓我著迷的特性有很多,其中最喜歡的是接口設(shè)計,他讓我們設(shè)計的東西具有美感。同樣反射也是我比較喜歡的一個特性,他讓程序自動運(yùn)行,動態(tài)加載成為了可能,同時也是現(xiàn)在很多流行框架所必不可少的特性,struts,hibernate等都是,spring本身就是基于反射的就更不用說了。細(xì)細(xì)想來,似乎很少有不涉及到反射的框架。我自己設(shè)計框架的時候,開始也都是運(yùn)用反射,但是越深入?yún)s讓我越疑惑,反射的效率一直是我設(shè)計框架的心病。

              今天在優(yōu)化InstantMVC的時候就考慮怎么提高自動封裝form的效率,struts是用的commons-beantuils,好像也沒人說struts的效率不高,誠然,beanUtils中很多有用方便的特性讓反射開發(fā)者著迷,但是通過我今天的測試,卻發(fā)現(xiàn)beanUtils的易用性要付出巨大的性能代價,雖然在現(xiàn)在這個年代,這么點(diǎn)性能不算什么,但是對于我這種執(zhí)著的人開發(fā)執(zhí)著的框架,還是對性能有種獨(dú)特的偏好,目前來說InstantMVC中用的是直接的反射簡單封裝,而InstantORM(我的持久層框架)中用到是自動生成pojo和相應(yīng)的pojo輔助類來實(shí)現(xiàn)動態(tài)高效(比直接的反射高效10-20倍)執(zhí)行Object的方法(一般是get和set),對于InstantMVC的form利用動態(tài)生成輔助類有一定的難度,不是說實(shí)現(xiàn)難度,而是對于運(yùn)用該框架的web開發(fā)者來說,不夠直接。所以還是主要考慮用反射的,廢話不說,下面開始今天的測試。

              首先,測試主要有三部分組成,測試創(chuàng)建對象的性能,測試set方法的性能,測試get方法的性能。我沒有看過beanUtils的源代碼,不過評我的經(jīng)驗(yàn)想想BeanUtils應(yīng)該是做了一些性能的優(yōu)化的,初步猜測是第一次運(yùn)行緩存Object的相應(yīng)東東(具體是什么也不知道),所以測試的時候都是從第二次開始,忽略第一次。下面是測試代碼(省略了異常拋出。)   

             
          public class MyBean {
              String name;
              
          int age;
              String[] firends;
              
          public static void main(String args[]) {
                  Object o1
          =beanUtilsCreate();
                  Object o2
          =javaCreate();
                  MyBean my
          =new MyBean();
                  
          long a=System.currentTimeMillis();
                 
                
                  
          for(int i=0;i<5000;i++){
                      
          //47
                      
          //beanUtilsCreate();
                      
          //15
                      
          //javaCreate();
                      
          //0
                      
          //manualCreate();
                      
                      
          //235
                      
          //beanUtilsSet(o1);
                      
          //40
                      
          //javaSet(o2);
                      
          //0
                      
          //manualSet(my);
                      
                      
          //203
                      
          //beanUtilsGet(o1);
                      
          //47
                      
          //javaGet(o2);
                      
          //0
                      
          //manualGet(my);
                  }
                  
          long b=System.currentTimeMillis();
                  System.out.println(b
          -a);
              }
              
              
              
          //===============下面是 beanUtils的方法
              public static Object beanUtilsCreate() {
                  Object ob
          =ConstructorUtils.invokeConstructor(MyBean.class,null);
                  
          return ob;
              }
              
          public static void beanUtilsSet(Object ob) {
                  BeanUtils.setProperty(ob, 
          "name""旺旺旺");
              }
              
          public static void beanUtilsGet(Object ob) {
                  BeanUtils.getProperty(ob, 
          "name");
              }
              
              
          //    ===============下面是 java自身的直接反射的方法
              public static Object javaCreate() {
                  Object ob
          =MyBean.class.newInstance();
                  
          return ob;
              }
              
          public static void javaSet(Object ob) {
                  Method m
          =MyBean.class.getDeclaredMethod("setName"new Class[]{String.class});
                  m.invoke(ob,
          new Object[]{"旺旺旺"});
              }
              
          public static void javaGet(Object ob) {
                  Method m
          =MyBean.class.getDeclaredMethod("getName"new Class[0]);
                  m.invoke(ob,
          new Object[0]);
              }
              
          //    ===============下面是 手動的創(chuàng)建對象
              public static MyBean manualCreate(){
                  MyBean my
          =new MyBean();
                  
          return my;
              }
              
          public static void manualSet(MyBean my){
                  my.setName(
          "旺旺旺");
              }
              
          public static void manualGet(MyBean my){
                  my.getName();
              }
              
              
              
              
          public int getAge() {
                  
          return age;
              }
              
          public void setAge(int age) {
                  
          this.age = age;
              }
              
          public String[] getFirends() {
                  
          return firends;
              }
              
          public void setFirends(String[] firends) {
                  
          this.firends = firends;
              }
              
          public String getName() {
                  
          return name;
              }
              
          public void setName(String name) {
                  
          this.name = name;
              }
          }

              上面代碼首先創(chuàng)建一個MyBean,簡單的name和age屬性,然后get和set方法,在main方法中首先構(gòu)建三個類:
          Object o1=beanUtilsCreate();
          Object o2
          =javaCreate();
          MyBean my
          =new MyBean();
          為了防止beanUtils內(nèi)部對第一次做了緩存操作而使測試不準(zhǔn)確。

          第二次開始連續(xù)循環(huán)5000次分別測試 Create,set,和get的性能。
          結(jié)果顯示如下:

          ===================================================
                 BeanUtils   java自己反射   手動
          創(chuàng)建:    47          15            0     
          set方法   235         40            0
          get方法   203         47            0

          ===================================================
          jdk 1.6,1G內(nèi)存,AMD 2600+

              從上面的結(jié)果可以看出,BeanUtils的性能確實(shí)不怎么樣,這樣的結(jié)果雖然在現(xiàn)代服務(wù)器都菜價了的年代,我還是要為struts和spring等基于反射的框架捏一把汗。不知道spring有沒有對反射做過優(yōu)化,不過上次看Ibatis的時候好像他提供了一個配置選項(xiàng)來增強(qiáng)字節(jié)碼的反射效率,大概就是那種動態(tài)創(chuàng)建字節(jié)碼的技術(shù)吧。




          --InstantMVC:j2ee輕量級mvc框架

          posted on 2008-06-07 16:31 剎那 閱讀(11683) 評論(12)  編輯  收藏 所屬分類: java性能分析

          Feedback

          # re: java反射性能測試分析[未登錄] 2008-06-07 19:40 Ryan

          反射生成對象,一般來說,一次生成多次使用,生成對象的時間對使用對象來說應(yīng)該算是小的,但是如果你只生成一次,其他的什么都不做,那么本身也沒什么意義,因?yàn)闆]有做任何動作  回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-06-07 20:46 剎那

          @Ryan
          恩,你說的有道理,一般生成一次都是緩存然后多次使用,但是對于有些應(yīng)用卻不竟然,比如struts的formBean,因?yàn)槭窃诙嗑€程情況下,所以不可能多吃重復(fù)應(yīng)用,再比如webwork的action,是非單利模式,也就是每次用戶請求都要創(chuàng)建一個action,同樣用到了反射。當(dāng)然可以用clone技術(shù)減少創(chuàng)建成本,但是不可否認(rèn),這種創(chuàng)建一次使用一次的情況還是有的。
          再說,就算創(chuàng)建一次使用多次,但是每次調(diào)用set和get的開銷還是比較大的。  回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-06-08 04:17 YYX

          對于Spring這種框架來說,一個bean生成了以后是長時間存在的。
          而對于beanUtils這種簡單應(yīng)用5000次也就是1~2百毫秒時間,大部分時間只是執(zhí)行一次,對于web應(yīng)用,從底層數(shù)據(jù)一直執(zhí)行至表現(xiàn)層,這點(diǎn)開銷可以忽略不計。
          執(zhí)行效能優(yōu)化以系統(tǒng)架構(gòu)選擇,儲存策略,數(shù)據(jù)表數(shù)據(jù)庫和SQL優(yōu)化為主。
          而且beanUtils也在節(jié)約開發(fā)時間同時也可以使代碼更為通用。
          另:不要把開源社區(qū)的人都當(dāng)成神了,像beanUtils這種代碼沒什么可以優(yōu)化的地方。  回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-06-08 08:30 剎那

          @YYX
          這位老兄一定沒做過webwork和spring整合開發(fā)。因?yàn)閣ebwork的action是非單利的,用spring整合的時候需要每次一個請求反射一個action,而不是你說的都是一次生成長期使用(雖然在大多數(shù)情況下,spring還是最好弄單利)。
          雖然我知道整個開銷對于web應(yīng)用是可以忽略的,但是能優(yōu)化,我還是要優(yōu)化的,因?yàn)楫吘棺龅氖强蚣茴惖臇|西,如果框架本身性能有問題,那么基于它上面的應(yīng)用就比較難說了。另外,beanUtils如果你作為一種tools,在平時開發(fā)的時候用用,那么沒什么問題,但是如果集成到通用框架中,我不敢茍同,因?yàn)楸旧硗ㄓ每蚣苤械慕M件被他人拿出來重用的可能性很小(保持框架內(nèi)通用可重用即可),權(quán)衡這些,還是覺得beanUtils這種東西不適合做通用框架下集成,但是卻是和在普通的應(yīng)用中使用。  回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-06-16 12:27 newroc

          每種JDK測試的效果會有些差別,我的結(jié)果是BeanUtils 要比自己 直接使用反射要快些的。  回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-06-16 16:06 剎那

          @newroc
          你的是jdk幾?我是1.6  回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-06-17 15:54 z-bro

          仔細(xì)閱讀了這段代碼,并且閱讀了beanutils-1.8.0 ConstructorUtils與setProperty代碼,很遺憾我沒有發(fā)現(xiàn)有優(yōu)化執(zhí)行效率的跡象存在.在ConstructorUtils部分程序結(jié)構(gòu)相對簡單,代碼冗余相對較小;而setProperty部分,有相當(dāng)部分log代碼(可以通過開關(guān)關(guān)閉),并且有大量的細(xì)致工作代碼.beanutils中在ConstructorUtils與setProperty部分也沒有緩存的機(jī)制存在.另外補(bǔ)充一句:剎那 的這份測試代碼都使用了java缺省的類加載器,這3種加載(創(chuàng)建)方式(BeanUtils,java自己反射,手動)在第一次之后,都是使用了ClassLoader的緩存,而并沒有重新讀類文件.
          結(jié)合 剎那 的分析報告,我個人認(rèn)為beanutils不能作為強(qiáng)調(diào)高效框架的首選,因?yàn)?quot;如果你只生成一次,其他的什么都不做,那么本身也沒什么意義",但是如果如YXX考慮的那樣,可能是個不錯的選擇

            回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-06-25 16:37 YYX

          @剎那
          spring 和struts2的整合項(xiàng)目 我正在做。
          你那個beanutils運(yùn)行一次要把bean里面的所有g(shù)etter和setter遍歷一次,當(dāng)比你其他的地方專門指定某方法執(zhí)行的慢多了,要比也要所有屬性get,set一次再和beanutils比。
          另外我說的這個性能差距可以忽略,的確是這樣的,從數(shù)據(jù)庫以后的邏輯運(yùn)算比起數(shù)據(jù)庫查詢需要的時間,本來就是可以忽略的。
          就好比一個億萬富翁,不會一大早出遠(yuǎn)門到便宜的地方去買菜。哪怕樓下的菜貴10倍,只要東西一樣,就行。  回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-06-25 16:50 YYX

          真正要提高性能,不是在這種小地方下手,而是整體架構(gòu)的設(shè)計,查詢語句,數(shù)據(jù)庫的配置,緩存的配置,運(yùn)算量的分布。這些方面改善一點(diǎn),比5000次copyProperties()節(jié)約時間還長。
            回復(fù)  更多評論   

          # re: java反射性能測試分析[未登錄] 2008-09-09 22:53 P

          看到beanUtil里面用set/getProperty()了嗎?人家為什么這么做?你那個類有通用性嗎?  回復(fù)  更多評論   

          # re: java反射性能測試分析 2008-12-08 13:24 WGQQL

          優(yōu)化是針對瓶頸來的,樓主列出這些數(shù)據(jù)只是指出這里存在優(yōu)化的可能性,并不是一定要怎么樣吧.
          優(yōu)化也分為2個方面:人和程序,優(yōu)化就是要這二者之間來取平衡,基本上的時候是人的效率太低,所以要犧牲一部分程序的效率來增加人的效率.  回復(fù)  更多評論   

          # re: java反射性能測試分析 2009-03-23 18:50 反射支持者

          你的機(jī)器很爛
          代碼不健壯  回復(fù)  更多評論   



          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 安陆市| 唐山市| 郧西县| 日照市| 龙海市| 海南省| 景泰县| 镶黄旗| 阳曲县| 象山县| 乌拉特前旗| 修水县| 奉新县| 江都市| 侯马市| 太保市| 商水县| 张家口市| 江油市| 古丈县| 峨山| 盐源县| 锡林郭勒盟| 崇州市| 西盟| 商城县| 广东省| 南郑县| 新闻| 安福县| 平远县| 翁源县| 香格里拉县| 墨江| 朔州市| 广德县| 辉南县| 武邑县| 东至县| 积石山| 太仓市|