posts - 297,  comments - 1618,  trackbacks - 0
          • ?盡可能使用堆棧變量

          ??????? 如果您頻繁存取變量,就需要考慮從何處存取這些變量。變量是 static 變量,還是堆棧變量,或者是類的實例變量?變量的存儲位置對存取它的代碼的性能有明顯的影響?例如,請考慮下面這段代碼:

          class ?StackVars
          {
          ??
          private ? int ?instVar;
          ??
          private ? static ? int ?staticVar;
          ??
          ??
          // 存取堆棧變量
          ?? void ?stackAccess( int ?val)
          ??
          {
          ????
          int ?j = 0 ;
          ????
          for ?( int ?i = 0 ;?i < val;?i ++ )
          ??????j?
          += ? 1 ;
          ??}

          ??
          ??
          // 存取類的實例變量
          ?? void ?instanceAccess( int ?val)
          ??
          {
          ????
          for ?( int ?i = 0 ;?i < val;?i ++ )
          ??????instVar?
          += ? 1 ;
          ??}
          ???
          ??
          ??
          // 存取類的?static?變量
          ?? void ?staticAccess( int ?val)
          ??
          {
          ????
          for ?( int ?i = 0 ;?i < val;?i ++ )
          ??????staticVar?
          += ? 1 ;
          ??}

          }
          ?????
          ????? 這段代碼中的每個方法都執行相同的循環,并反復相同的次數。唯一的不同是每個循環使一個不同類型的變量遞增。方法 stackAccess 使一個局部堆棧變量遞增,instanceAccess 使類的一個實例變量遞增,而 staticAccess 使類的一個 static 變量遞增。

          ????? instanceAccess 和 staticAccess 的執行時間基本相同。但是,stackAccess 要快兩到三倍。存取堆棧變量如此快是因為,JVM 存取堆棧變量比它存取 static 變量或類的實例變量執行的操作少。

          ??? 查看字節碼揭示了堆棧變量效率更高的原因。JVM 是一種基于堆棧的虛擬機,因此優化了對堆棧數據的存取和處理。所有局部變量都存儲在一個局部變量表中,在 Java 操作數堆棧中進行處理,并可被高效地存取。存取 static 變量和實例變量成本更高,因為 JVM 必須使用代價更高的操作碼,并從常數存儲池中存取它們。(常數存儲池保存一個類型所使用的所有類型、字段和方法的符號引用。)

          ??? 通常,在第一次從常數存儲池中訪問 static 變量或實例變量以后,JVM 將動態更改字節碼以
          使用效率更高的操作碼。盡管有這種優化,堆棧變量的存取仍然更快。

          ??? 考慮到這些事實,就可以重新構建前面的代碼,以便通過存取堆棧變量而不是實例變量或
          static 變量使操作更高效。請考慮修改后的代碼:

          class?StackVars
          {
          ??
          //與前面相同
          ??void?instanceAccess(int?val)
          ??
          {
          ????
          int?j?=?instVar;
          ????
          for?(int?i=0;?i<val;?i++)
          ??????j?
          +=?1;
          ????instVar?
          =?j;
          ??}
          ??
          ??
          ??
          void?staticAccess(int?val)
          ??
          {
          ????
          int?j?=?staticVar;
          ????
          for?(int?i=0;?i<val;?i++)
          ??????j?
          +=?1;
          ????staticVar?
          =?j;
          ??}

          }
          ????
          ??? 方法 instanceAccess 和 staticAccess 被修改為將它們的實例變量或 static 變量復制到局部堆棧變量中。當變量的處理完成以后,其值又被復制回實例變量或 static 變量中。這種簡單的更改明顯提高了instanceAccess 和 staticAccess 的性能。這三個方法的執行時間現在基本相同,instanceAccess 和 staticAccess 的執行速度只比 stackAccess 的執行速度慢大約 4%。
          ?/*======== 循環的最佳化?========*/
          把循環
          ?for (int i = 0; i < 100; i++)
          ?{}
          改成
          ?for (int i = 99; i >= 0; i--)
          ?{}

          后,速度會更快,之所以會有效的提升,是因為如果數值要與0比較,在底層都有較簡單的指令可以應,也因此加速了程序的執行。其它(> >= < <= !=)都可以這樣考慮.
          ??? String比StringBuffer節省內存,但StringBuffer運行速度比String快

          package?com;

          public?class?Test?
          {
          ?
          public?static?void?main(String[]?args)?
          ?
          {
          ??Runtime?rt?
          =?Runtime.getRuntime();
          ??
          long?start?=?rt.totalMemory()?-?rt.freeMemory();
          ??System.out.println(
          "memory?used?start:?"?+?start);??
          ??String?sum?
          =?"";
          ??
          for?(int?i?=?0;?i?<?5000;?i++)
          ??
          {
          ???sum?
          =?sum?+?"+"?+?i;
          ??}

          ??
          long?end?=?rt.totalMemory()?-?rt.freeMemory();
          ??System.out.println(
          "memory?used?end:?"?+?end);
          ??System.out.println(
          "總共消耗了內存:?"?+?(end?-?start));
          ?}

          }



          輸出:
          memory used start: 132280
          memory used end: 189648
          總共消耗了內存: 57368
          package?com;

          public?class?Test?
          {
          ?
          public?static?void?main(String[]?args)?
          ?
          {
          ??Runtime?rt?
          =?Runtime.getRuntime();
          ??
          long?start?=?rt.totalMemory()?-?rt.freeMemory();
          ??System.out.println(
          "memory?used?start:?"?+?start);??
          ??StringBuffer?sum?
          =?new?StringBuffer("");
          ??
          for?(int?i?=?0;?i?<?5000;?i++)
          ??
          {
          ???sum?
          =?sum.append("+").append(i);
          ??}

          ??
          long?end?=?rt.totalMemory()?-?rt.freeMemory();
          ??System.out.println(
          "memory?used?end:?"?+?end);
          ??System.out.println(
          "總共消耗了內存:?"?+?(end?-?start));
          ?}

          }

          輸出:
          memory used start: 132192
          memory used end: 281056
          總共消耗了內存: 148864


          ??? 書上說使用StringBuffer比Sting更能節省內存,但從上面可以看出,好像StringBuffer消耗的內存多,

          ???? 經過測試,發現String比StringBuffer節省內存,但StringBuffer運行速度比String快。

          • ?? 不用new關鍵詞創建類的實

          ???? 對象的創建是個很昂貴的工作,所以我們應當盡量減少對象的創建,在需要的時候聲明它,初始化它,不要重復初始化一個對象,盡量能做到再使用,而用完后置null有利于垃圾收集。讓類實現Cloneable接口,同時采用工廠模式,將減少類的創建,每次都是通過clone()方法來獲得對象。另外使用接口也能減少類的創建。對于成員變量的初始化也應盡量避免, 特別是在一個類派生另一個類時。

            ?異常拋出對性能不利。拋出異常首先要創建一個新的對象。Throwable接口的構造函數調用名為, fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法檢查堆棧,收集調用跟蹤信息。只要有異常被拋出,JVM就必須調整調用堆棧,因為在處理過程中創建了一個新的對象。 異常只能用于錯誤處理,不應該用來控制程序流程。

            此外, 建議關閉Debug輸出,盡量少用串行化、同步操作和耗時昂貴的服務(如Date())。??????

          • ?????? 使用合適的類型

          ????? 當原始類型不能滿足我們要求時,使用復雜類型。String和StringBuffer的區別自不必說了,是我們使用最多的類型,在涉及到字符運算時,強烈建議使用StringBuffer。在做String匹配時使用intern()代替equal()。

            帶有final修飾符的類是不可派生的, 如果指定一個類為final,則該類所有的方法都是final。

            Java編譯器會尋找機會內聯所有的final方法,這將能夠使性能平均提高50%。類的屬性和方式使用final或者static修飾符也是有好處的。

            ?調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中,速度較快。所以盡量使用局部變量。

            ?ArrayList和Vector,HashMap和Hashtable是我們經常用到的類,前者不支持同步,后者支持同步,前者性能更好,大多數情況下選擇前者。

          posted on 2007-03-09 13:33 阿蜜果 閱讀(1049) 評論(3)  編輯  收藏 所屬分類: Java


          FeedBack:
          # re: java性能優化
          2007-03-09 18:06 | BeanSoft
          呵呵, 不錯, Amigo 越來越厲害了.  回復  更多評論
            
          # re: java性能優化
          2007-03-09 20:53 | 施偉
          這么有深度。。。看來大家要加油,向Amigo學習。。。  回復  更多評論
            
          # re: java性能優化 [未登錄]
          2007-03-09 21:36 | 阿蜜果
          哈哈,可惜是轉載的,存儲了很久,覺得很好,放上來了,原文出處都不知道:(  回復  更多評論
            
          <2007年3月>
          25262728123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

                生活將我們磨圓,是為了讓我們滾得更遠——“圓”來如此。
                我的作品:
                玩轉Axure RP  (2015年12月出版)
                

                Power Designer系統分析與建模實戰  (2015年7月出版)
                
               Struts2+Hibernate3+Spring2   (2010年5月出版)
               

          留言簿(263)

          隨筆分類

          隨筆檔案

          文章分類

          相冊

          關注blog

          積分與排名

          • 積分 - 2296322
          • 排名 - 3

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 开化县| 海宁市| 天长市| 阿拉尔市| 嵩明县| 勃利县| 牟定县| 库尔勒市| 崇仁县| 定安县| 读书| 雅安市| 平谷区| 资兴市| 屏东县| 武强县| 闻喜县| 巴林右旗| 原阳县| 武宣县| 营山县| 宁国市| 焦作市| 桃园市| 开江县| 莒南县| 盘锦市| 长治县| 兰坪| 邵阳市| 凉城县| 宣汉县| 郎溪县| 天等县| 舟山市| 余庆县| 彩票| 南乐县| 盐津县| 读书| 天津市|