熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

為JAVA性能而設計(2)

2022-06-13   來源: Java高級技術 

  作者eclipse
  
  為性能而設計 第二部分: 減少對象創建[/b]
  
  From Java World
  
  [b]在設計 Java 類的時候避免性能上的冒險[/b]
  
  [b][u]概要[/u][/b]
  
  許多通常的 Java 性能問題都起源於在設計過程早期中的類設計的思想 早在許多開發者
  開始考慮性能問題之前 在這個系列中 Brian Goetz 討論了通常的 Java 性能上的冒險
  以及怎麼在設計時候避免它們 在第二部分 他討論了減少臨時對象創建的一些技術
  ( 字)
  
  By Brian Goetz
  
  翻譯 by SuperMMX
  
  閱讀整個為性能而設計系列:
  
  第一部分: 接口事宜
  第二部分: 減少對象創建
  第三部分: 遠程接口 (March )
  
  雖然許多程序員把性能管理一直推遲到開發過程的最後 性能考慮應該從第一天起就和設
  計周期結合在一起 這個系列探索一些早期的設計思想能夠極大影響應用程序性能的方法
  在這篇文章裡 我繼續探索大量臨時對象創建的問題 並且提供一些避免它們的一些技術
  
  臨時對象就是一些生命周期比較短的對象 一般用於保存其他數據而再沒有其他用途
  序員一般用臨時變量向一個方法傳遞數據或者從一個方法返回數據 第一部分探討了臨時
  對象是怎樣給一個程序的性能帶來負面的沖擊 以及一些類接口的設計思想怎樣提供了臨
  時對象的創建 避免了那些接口的創建 你就能極大地減少那些影響你的程序性能的臨時
  對象創建的需求
  
  [b][u]只是對 String 說不嗎?[/u][/b]
  
  當它要創建臨時變量時 String 類是最大的罪人中的一個 為了演示 在第一部分我寫了
  一個正規表達式匹配的例子 通過和一個類似的但是經過仔細設計的接口相比較 演示了
  看起來無害的接口是怎樣引起大量對象的創建 而慢上幾倍 這裡是原來的和好一些的類
  的接口:
  
  BadRegExpMatcher
  
  [code]
  public class BadRegExpMatcher {
   public BadRegExpMatcher(String regExp);
   /** Attempts to match the specified regular expression against the input
   text returning the matched text if possible or null if not */
   public String match(String inputText);
  }
  [/code]
  
  BetterRegExpMatcher
  
  [code]
  class BetterRegExpMatcher {
   public BetterRegExpMatcher();
   /** Provide matchers for multiple formats of input String
   character array and subset of character array Return if no
   match was made; return offset of match start if a match was
   made */
   public int match(String inputText);
   public int match(char[] inputText);
   public int match(char[] inputText int offset int length);
   /** If a match was made returns the length of the match; between
   the offset and the length the caller should be able to
   reconstruct the match text from the offset and length */
   public int getMatchLength();
   /** Convenience routine to get the match string in the event the
   caller happens to wants a String */
   public String getMatchText();
  }
  [/code]
  
  大量使用 BadREgExpMatcher 的程序比使用 BtterRegExpMatcher 的要慢好多 首先
  調用者不得不創建一個 String 傳入 match() 接著 match() 又創建了一個 String 來
  返回匹配的文本 結果是每次調用都有兩個對象創建 看起來不多 但是如果要經常調用
  match() 這些對象創建帶給性能的代價就太打了 BadRegExpMatcher 的性能問題不是在
  它的實現中 而是它的接口; 象它定義的接口 沒有辦法避免一些臨時變量的創建
  
  BetterRegExpMatcher 的 match() 用原類型(整數和字符數組)代替了 String 對象; 不需
  要創建中間對象來在調用者和 match() 之間傳遞信息
  
  既然在設計時候避免性能問題要比寫完整個系統以後再修改要容易一些 你應該注意你的
  類中控制對象創建的方法 在 RegExpMatcher 的例子中 它的方法要求和返回 String
  對象 就應該為潛在的性能冒險提個警告信號 因為 String 類是不可變的 除了最常用
  以外 所有的 String 參數在每次調用處理函數時都需要創建一個新的 String
  
  [b][u]不可變性對於性能來說是否很壞?[/u][/b]
  
  因為 String 經常和大量的對象創建聯系在一起 一般來說歸咎於它的不可變性 許多
  程序員認為不可變的對象與生俱來對性能沒有好處 但是 事實多少會更復雜一些
  際上 不可變性有時候提供了性能上的優勢 可變性的對象有時候導致性能問題 不管可
  變性對性能來說有幫助或者有害 依賴於對象是怎麼使用的
  
  程序經常處理和修改文本字符串 和不可變性非常不匹配 每次你想處理一個 String
  想查找和解析出前綴或者子串 變小寫或者大寫 或者把兩個字符串合並 你必須創建
  一個新的 String 對象 (在合並的情況下 編譯器也會隱藏地創建一個 StringBuffer()
  對象)
  
  另一個方面 一個不可變的對象的一個引用可以自由共享 而不用擔心被引用的對象要被
  修改 這個比可變對象提供性能優勢 就象下一節例子所說的
  
  [b][u]可變的對象有它們自己的臨時對象問題 [/u][/b]
  
  在 RegExpMatcher 的例子中 你看見了 當一個方法返回一個 String 類型時 它通常
  需要新建一個 String 對象 BadRegExpMatcher 的一個問題就是 match() 返回一個對
  象而不是一個原類型 但是只因為一個方法返回一個對象 不意味著必須有一個新對
  象創建 考慮一下 javaawt 中的幾何類 象 Point 和 Rectangle 一個 Rectangle
  只是四個整數(x y 寬度 長度)的容器 AWT Component 類存儲組件的位置 通過
  getBounds()作為一個Rectangle 返回
  
  [code]
  public class Component {
  
   public Rectangle getBounds();
  }
  [/code]
  
  在上面的例子中 getBounds() 只是一個存儲元 它只使一些 Component 內部的一
  些狀態信息可用 getBounds() 需要創建它返回的 Rectangle 嗎? 可能 考慮一下下面
  getBounds() 可能的實現
  
  [code]
  public class Component {
  
   protected Rectangle myBounds;
   public Rectangle getBounds() { return myBounds; }
  }
  [/code]
  
  當一個調用者調用上面例子中的 getBounds() 沒有新對象創建 因為組件已經知道它
  在哪裡 所以 getBounds() 效率很高 但是 Rectangle 的可變性又有了其他問題
  一個調用者運行一下程序會發生什麼呢?
  
  [code]
   Rectangle r = componentgetBounds();
  
   rheight *= ;
  [/code]
  
  因為 Rectangle 是可變的 它在 Component 不知道的情況下使 Component 移動 對象
  AWT 這樣的 GUI 工具箱來說 這是個災難 因為當一個組件移動以後 屏幕需要重繪
  件監聽器需要被通知 等等 所以上面的實現 ComponentgetBounds() 的代碼看起來很
  危險 一個安全一點的實現就象下面這樣:
  
  [code]
   public Rectangle getBounds() {
   return new Rectangle(myBoundsx myBoundsy
   myBoundsheight myBoundswidth);
   }
  [/code]
  
  但是現在 每一個 getBounds() 的調用都創建一個新對象 就象 RegExpMatcher 一樣
  實際上 下面的代碼片段創建了 個臨時對象:
  
  [code]
   int x = componentgetBounds()x;
   int y = componentgetBounds()y;
   int h = componentgetBounds()height;
   int w = componentgetBounds()width;
  [/code]
  
  在 String 的情況中 對象創建是必要的 因為 String 是不可變的 但在這個例子中
  對象的創建也是必要的 因為 Rectangle 是可變的 我們使用 String 避免了這個問題
  在我們的接口中沒有使用對象 雖然在 RegExpMatcher 的情況下很好 這個方法不總是
  可行的或者是希望的 幸運的是 你可以在實際類的時候可以使用一些技巧 來免除太多
  小對象的問題 而不是完全避免小對象
  
  [b][u]減少對象的技巧 : 加上好的存取函數[/u][/b]
  
  在 Swing 工具箱的初始版本中 對象小對象的臨時創建 象 Point Rectangle 和 Dimension
  極大地阻礙了性能 把它們放在一個 Point 或者 Rectangle 中來一次返回多個值 看起
  來更有效 實際上 對象的創建比多個方法調用代價更高 在 Swing 的最後發布之前
  過給 Component 和其他一些類加一些新的存取方法 問題就簡單地解決了 就象下面這樣:
  
  [code]
   public int getX() { return myBoundsx; }
   public int getY() { return myBoundsy; }
   public int getHeight() {
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27468.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.