乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      找到一篇性能測(cè)試的好文,簡(jiǎn)單實(shí)用,收藏之。...

       鬼迷心竅 2008-01-26

      Java程序性能測(cè)試

      1 概述

      在開(kāi)發(fā)中,性能測(cè)試是設(shè)計(jì)初期容易忽略的問(wèn)題,開(kāi)發(fā)人員會(huì)為了解決一個(gè)問(wèn)題而“不擇手段”,作者所參與的項(xiàng)目中也遇到了類似問(wèn)題,字符串拼接、大量的網(wǎng)絡(luò)調(diào)用和數(shù)據(jù)庫(kù)訪問(wèn)等等都對(duì)系統(tǒng)的性能產(chǎn)生了影響,可是大家不會(huì)關(guān)心這些問(wèn)題,“CPU速度在變快”,“內(nèi)存在變大”,并且,“好像也沒(méi)有那么慢吧”。

      有很多商業(yè)的性能測(cè)試軟件可供使用,如Jprofiler、JProbe Profiler等,但在開(kāi)發(fā)當(dāng)中顯得有些遙遠(yuǎn)而又昂貴。

      2 目標(biāo)

      本文將講述如何利用Java語(yǔ)言本身提供的方法在開(kāi)發(fā)中進(jìn)行性能測(cè)試,找到系統(tǒng)瓶頸,進(jìn)而改進(jìn)設(shè)計(jì);并且在盡量不修改測(cè)試對(duì)象的情況下進(jìn)行測(cè)試。

      3 預(yù)備知識(shí)

      面向?qū)ο缶幊掏ㄟ^(guò)抽象繼承采用模塊化的思想來(lái)求解問(wèn)題域,但是模塊化不能很好的解決所有問(wèn)題。有時(shí),這些問(wèn)題可能在多個(gè)模塊中都出現(xiàn),像日志功能,為了記錄每個(gè)方法進(jìn)入和離開(kāi)時(shí)的信息,你不得不在每個(gè)方法里添加log("in some method")等信息。如何解決這類問(wèn)題呢?將這些解決問(wèn)題的功能點(diǎn)散落在多個(gè)模塊中會(huì)使冗余增大,并且當(dāng)很多個(gè)功能點(diǎn)出現(xiàn)在一個(gè)模塊中時(shí),代碼變的很難維護(hù)。因此,AOPAspect Oriented Programming)應(yīng)運(yùn)而生。如果說(shuō)OOPAobject Oriented Programming)關(guān)注的是一個(gè)類的垂直結(jié)構(gòu),那么AOP是從水平角度來(lái)看待問(wèn)題。

      動(dòng)態(tài)代理類可以在運(yùn)行時(shí)實(shí)現(xiàn)若干接口,每一個(gè)動(dòng)態(tài)代理類都有一個(gè)Invocation handler對(duì)象與之對(duì)應(yīng),這個(gè)對(duì)象實(shí)現(xiàn)了InvocationHandler接口,通過(guò)動(dòng)態(tài)代理的接口對(duì)動(dòng)態(tài)代理對(duì)象的方法調(diào)用會(huì)轉(zhuǎn)而會(huì)調(diào)用Invocation handler對(duì)象的invoke方法,通過(guò)動(dòng)態(tài)代理實(shí)例、方法對(duì)象和參數(shù)對(duì)象可以執(zhí)行調(diào)用并返回結(jié)果。

      說(shuō)到AOP,大家首先會(huì)想到的是日志記錄、權(quán)限檢查和事務(wù)管理,是的,AOP是解決這些問(wèn)題的好辦法。本文根據(jù)AOP的思想,通過(guò)動(dòng)態(tài)代理來(lái)解決一類新的問(wèn)題——性能測(cè)試(performance testing)。

      性能測(cè)試主要包括以下幾個(gè)方面:

      l         計(jì)算性能:可能是人們首先關(guān)心的,簡(jiǎn)單的說(shuō)就是執(zhí)行一段代碼所用的時(shí)間

      l         內(nèi)存消耗:程序運(yùn)行所占用的內(nèi)存大小

      l         啟動(dòng)時(shí)間:從你啟動(dòng)程序到程序正常運(yùn)行的時(shí)間

      l         可伸縮性(scalability)

      l         用戶察覺(jué)性能(perceived performance):不是程序?qū)嶋H運(yùn)行有多快,而是用戶感覺(jué)程序運(yùn)行有多快.

      本文主要給出了計(jì)算性能測(cè)試和內(nèi)存消耗測(cè)試的可行辦法。

       

      4 計(jì)算性能測(cè)試

      4.1 目標(biāo):

      通過(guò)該測(cè)試可以得到一個(gè)方法執(zhí)行需要的時(shí)間

      4.2實(shí)現(xiàn):

      Java為我們提供了System. currentTimeMillis()方法,可以得到毫秒級(jí)的當(dāng)前時(shí)間,我們?cè)谝郧暗某绦虍?dāng)中一定也寫(xiě)過(guò)類似的代碼來(lái)計(jì)算執(zhí)行某一段代碼所消耗的時(shí)間。

                 long start=System.currentTimeMillis();

                 doSth();

                 long end=System.currentTimeMillis();

                 System.out.println("time lasts "+(end-start)+"ms");

      但是,在每個(gè)方法里面都寫(xiě)上這么一段代碼是一件很枯燥的事情,我們通過(guò)Javajava.lang.reflect.Proxyjava.lang.reflect.InvocationHandler利用動(dòng)態(tài)代理來(lái)很好的解決上面的問(wèn)題。

      我們要測(cè)試的例子是java.util.LinkedListjava.util.ArrayListget(int index)方法,顯然ArrayList要比LinkedList高效,因?yàn)榍罢呤请S機(jī)訪問(wèn),而后者需要順序訪問(wèn)。

      首先我們創(chuàng)建一個(gè)接口

      public interface Foo {

          public void testArrayList();

          public void testLinkedList();

      }

      然后我們創(chuàng)建測(cè)試對(duì)象實(shí)現(xiàn)這個(gè)接口

      public class FooImpl implements Foo {

       

             private List link=new LinkedList();

             private List array=new ArrayList();

       

             public FooImpl()

             {

                 for(int i=0;i<10000;i++)

                 {

                        array.add(new Integer(i));

                        link.add(new Integer(i));

                 }           

             }

         

          public void testArrayList()

          {

                 for(int i=0;i<10000;i++)

                        array.get(i);

          }

         

          public void testLinkedList()

          {

                 for(int i=0;i<10000;i++)

                        link.get(i);

          }

      }

      接下來(lái)我們要做關(guān)鍵的一步,實(shí)現(xiàn)InvocationHandler接口

      import java.lang.reflect.InvocationHandler;

      import java.lang.reflect.Method;

      import java.lang.reflect.*;

       

      public class Handler implements InvocationHandler {

       

             private Object obj;

       

          public Handler(Object obj) {

              this.obj = obj;

          }

       

          public static Object newInstance(Object obj) {

              Object result = Proxy.newProxyInstance(obj.getClass().getClassLoader(),

                      obj.getClass().getInterfaces(), new Handler(obj));

       

              return (result);

          }

       

          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

              Object result;

              try {

                  System.out.print("begin method " + method.getName() + "(");

                  for (int i = 0; args != null && i < args.length; i++) {

       

                      if (i > 0) System.out.print(",");

                      System.out.print(" " +

                              args[i].toString());

                  }

                  System.out.println(" )");

                  long start=System.currentTimeMillis();

                  result = method.invoke(obj, args);

                  long end=System.currentTimeMillis();

                  System.out.println("the method "+method.getName()+" lasts "+(end-start)+"ms");

              } catch (InvocationTargetException e) {

                  throw e.getTargetException();

              } catch (Exception e) {

                  throw new RuntimeException

                          ("unexpected invocation exception: " +

                          e.getMessage());

              } finally {

                  System.out.println("end method " + method.getName());

              }

              return result;

          }

      }

      最后,我們創(chuàng)建測(cè)試客戶端,

      public class TestProxy {

          public static void main(String[] args) {

              try {

                  Foo foo = (Foo) Handler.newInstance(new FooImpl());

                  foo.testArrayList();

                  foo.testLinkedList();

              } catch (Exception e) {

                  e.printStackTrace();

              }

      }

      }

      運(yùn)行的結(jié)果如下:

      begin method testArrayList( )

      the method testArrayList lasts 0ms

      end method testArrayList

      begin method testLinkedList( )

      the method testLinkedList lasts 219ms

      end method testLinkedList

      使用動(dòng)態(tài)代理的好處是你不必修改原有代碼FooImpl,但是一個(gè)缺點(diǎn)是你不得不寫(xiě)一個(gè)接口,如果你的類原來(lái)沒(méi)有實(shí)現(xiàn)接口的話。

      4.3擴(kuò)展

      在上面的例子中演示了利用動(dòng)態(tài)代理比較兩個(gè)方法的執(zhí)行時(shí)間,有時(shí)候通過(guò)一次簡(jiǎn)單的測(cè)試進(jìn)行比較是片面的,因此可以進(jìn)行多次執(zhí)行測(cè)試對(duì)象,從而計(jì)算出最差、最好和平均性能。這樣,我們才能“加快經(jīng)常執(zhí)行的程序的速度,盡量少調(diào)用速度慢的程序”。

       

      5 內(nèi)存消耗測(cè)試

      5.1 目標(biāo)

      當(dāng)一個(gè)java應(yīng)用程序運(yùn)行時(shí),有很多需要消耗內(nèi)存的因素存在,像對(duì)象、加載類、線程等。在這里只考慮程序中的對(duì)象所消耗的虛擬機(jī)堆空間,這樣我們就可以利用Runtime 類的freeMemory()totalMemory()方法。

      5.2 實(shí)現(xiàn)

      為了方便期間,我們首先添加一個(gè)類計(jì)算當(dāng)前內(nèi)存消耗。

      class Memory

      {

             public static long used()

             {

                    long total=Runtime.getRuntime().totalMemory();

                    long free=Runtime.getRuntime().freeMemory();

                    return (total-free);

             }

      }

      然后修改Handler類的invoke()方法。

      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

              Object result;

              try {

                  System.out.print("begin method " + method.getName() + "(");

                  for (int i = 0; args != null && i < args.length; i++) {

       

                      if (i > 0) System.out.print(",");

                      System.out.print(" " +

                              args[i].toString());

                  }

                  System.out.println(" )");

                  long start=Memory.used();

                  result = method.invoke(obj, args);

                  long end=Memory.used();

                  System.out.println("memory increased by "+(end-start)+"bytes");

              } catch (InvocationTargetException e) {

                  throw e.getTargetException();

              } catch (Exception e) {

                  throw new RuntimeException

                          ("unexpected invocation exception: " +

                          e.getMessage());

              } finally {

                  System.out.println("end method " + method.getName());

              }

              return result;

          }

      同時(shí)我們的測(cè)試用例也做了一下改動(dòng),測(cè)試同樣一個(gè)顯而易見(jiàn)的問(wèn)題,比較一個(gè)長(zhǎng)度為1000ArrayListHashMap所占空間的大小,接口、實(shí)現(xiàn)如下:

      public interface MemoConsumer {

             public void creatArray();

             public void creatHashMap();

      }

      public class MemoConsumerImpl implements MemoConsumer {

       

             ArrayList arr=null;

             HashMap hash=null;

       

             public void creatArray() {

       

                    arr=new ArrayList(1000);

             }

             public void creatHashMap() {

                    hash=new HashMap(1000);

             }

      }

      測(cè)試客戶端代碼如下:

                     MemoConsumer arrayMemo=(MemoConsumer)Handler.newInstance(new MemoConsumerImpl ());

                     arrayMemo.creatArray();

                     arrayMemo.creatHashMap();

      測(cè)試結(jié)果如下:

      begin method creatArray( )

      memory increased by 4400bytes

      end method creatArray

      begin method creatHashMap( )

      memory increased by 4480bytes

      end method creatHashMap

      結(jié)果一幕了然,可以看到,我們只需要修改invoke()方法,然后簡(jiǎn)單執(zhí)行客戶端調(diào)用就可以了。

      6 結(jié)束語(yǔ)

             AOP通過(guò)分解關(guān)注點(diǎn)和OOP相得益彰,使程序更加簡(jiǎn)潔易懂,通過(guò)Java語(yǔ)言本身提供的動(dòng)態(tài)代理幫助我們很容易分解關(guān)注點(diǎn),取得了較好的效果。不過(guò)測(cè)試對(duì)象必須實(shí)現(xiàn)接口在一定程度上限制了動(dòng)態(tài)代理的使用,可以借鑒Spring中使用的CGlib來(lái)為沒(méi)有實(shí)現(xiàn)任何接口的類創(chuàng)建動(dòng)態(tài)代理。

      7 參考資料

      本文中提到的一些性能測(cè)試概念主要來(lái)自http://java./docs/books/performance/

      一些AOP的概念來(lái)自Jbosshttp://www./index.html?module=html&op=userdisplay&id=developers/projects/jboss/aop

      動(dòng)態(tài)代理和AOP的某些知識(shí)來(lái)自http://www./docs/reference/aop.html

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多