中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JAVA性能設計方法是什么

發布時間:2021-12-30 17:24:51 來源:億速云 閱讀:108 作者:iii 欄目:編程語言

本篇內容介紹了“JAVA性能設計方法是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

  概要
  許多通常的 Java 性能問題都起源于在設計過程早期中的類設計的思想, 早在許多開發者開始考慮性能問題之前. 在這個系列中, Brian Goetz討論了通常的 Java性能上的冒險以及怎么在設計時候避免它們.


  許多程序員在開發周期的后期才可是考慮性能管理. 他們常常把性能優化拖延到最后, 希望能完全避免 -- 有時候這種策略是成功的. 但是早期的設計思想可以影響性能優化的需求及其成功. 如果性能是你的程序的一個重要指標, 那么性能管理應該從第一天起就和設開發周期整合在一起.

  這個系列探索一些早期的設計思想能夠極大影響應用程序性能的方法. 在這篇文章中, 我專注于最通常的性能問題中的一個: 臨時變量的創建. 一個類的對象創建方式常常在設計時候就確定了的 -- 但不是故意的 --, 就為后來的性能問題種下了種子.

  性能問題有各種形式. 最容易調整的是那些你簡單地為計算選擇了一個錯誤的算法 -- 就象使用使用冒泡算法來對一個大數據集進行排序, 或者在使用一個經常使用的數據項時不是做緩沖, 而是每次都計算. 你可以使用概要分析來簡單地找出這些瓶頸, 一旦找到了,你可以很容易地改正. 但是, 許多 Java 性能問題來自一個更深的, 更難改正的源頭 -- 一個程序組件的接口設計.

  今天大多數程序是由內部開發的或者外部買來的組件構建而成. 甚至在程序不是很大地依于已經存在的組件時, 面向對象的設計過程也鼓勵應用程序包裝成組件, 這樣就簡化了設計, 開發和測試過程. 這些優勢是不可否認的, 你應該認識到這些組件實現的接口可能極大地影響使用它們的程序的行為和性能.

  在這一點上, 你可能要問什么樣的接口和性能相關. 一個類的接口不僅定義了這個類可以實現那些功能, 也可以定義它的對象創建行為和使用它的方法調用序列. 一個類怎樣定義它的構造函數和方法決定了一個對象是否可以重用, 它的方法是否要創建 -- 或者要求它的客戶端創建 -- 中間對象,  以及一個客戶端需要調用多少方法來使用這個類.這些因素都會影響程序的性能.

  注意對象的創建

  一個最基本的 Java 性能管理原則就是: 避免大量的對象創建. 這不是說你應該不創建任何對象而放棄面向對象的好處. 但是你必須在執行性能相關的代碼時, 在緊循環中注意對象的創建. 對象的創建是如此地高代價, 以至于你應該在要求性能的情況下避免不必要的臨時或者中間對象的創建.

  String 類是在那些處理文本的程序中對象創建的主要來源. 因為 String 是不可修改的,每當一個 String 修改或創建, 就必須創建一個新的對象. 結果就是, 關注性能的程序應該避免大量 String 的使用. 但是, 這通常是不可能的. 甚至當你從你的代碼中完全除去對 String 的依賴, 你常常會發現你自己在使用一些具有根據 String 定義的接口的組件.所以, 你最后不得不使用 String.

  例子: 正規表達式匹配

  作為一個例子, 假設你寫一個叫做 MailBot 的郵件服務器. MailBot 需要處理 MIME 頭格式 -- 象發送日期或者發送者的 email 地址 -- 在每個信息的頂部. 使用一個匹配正規表達式的組件來使處理 MIME 頭的過程簡單一些. MailBot 足夠聰明, 不為每個頭的行或者頭的元素創建一個 String 對象. 相反, 它用輸入的文本填充了一個字符緩沖區, 通過對緩沖區的索引來確定要處理的頭的位置. MailBot 會調用正規表達式匹配器來處理每個頭行, 所以匹配器的性能就非常重要. 我們以一個正規表達式匹配器類的拙劣的接口作為例子:

public class AwfulRegExpMatcher {
 /** Create a matcher with the given regular expression and which will
     operate on the given input string */
 public AwfulRegExpMatcher(String regExp, String inputText);
 /** Retrieve the next match of the pattern against the input text,
     returning the matched text if possible or null if not */
 public String getNextMatch();
}

  甚至在這個類實現了一個有效的正規表達式匹配的算法的時候, 任何大量使用它的程序仍然難以忍受. 既然匹配器對象和輸入的文本聯系起來, 每一次你調用它, 你必須創建一個新的匹配器對象. 既然你的目標是減少不必要的對象的創建, 那么使這個匹配器可以賾將會是一個明顯的開始.

  下面的類定義演示了你的匹配器的另一個可能的接口, 允許你重用這個匹配器, 但仍然很壞.

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);
 /** Get the next match against the input text, or return null if no match */
 public String getNextMatch();
}

  忽略正規表達式匹配中的精細點 -- 象返回匹配的子表達式, 這個看起來無害的類定義會出什么問題呢? 從功能上來看, 沒有. 但是從性能的角度來看, 許多. 首先, 匹配器需要它的調用者創建一個 String 來代表要匹配的文本. MailBot 試圖避免創建 String對象, 但是當它要找到一個要做正規表達式解析的頭時, 它不得不創建一個 String 來滿足 BadRegExpMatcher:

BadRegExpMatcher dateMatcher = new BadRegExpMatcher(...);
while (...) {
 ...
 String headerLine = new String(myBuffer, thisHeaderStart,
 thisHeaderEnd-thisHeaderStart);
 String result = dateMatcher.match(headerLine);
 if (result == null) { ... }
}

  第二, 匹配器創建了結果字符串甚至當 MailBot 只關心是否匹配了, 不需要匹配的文本時,這意味著要簡單使用 BadRegExpMatcher 來確認一個日期頭是否匹配一個特定的格式, 你必須創建兩個 String 對象 -- 匹配器的輸入和匹配的結果. 兩個對象可能看起來不多,但是如果你給 MailBot 處理的每個郵件的每個頭行都創建兩個對象, 這會極大地影響性能. 錯誤不在于 MailBot 的設計, 而在于 BadRegExpMatcher 類的設計 -- 或者使用.

  注意返回一個輕量型的 Match 對象 -- 可以提供 getOffset(), getLength(), egetMatchString() 方法 -- 而不是返回一個 String, 這不會很大提高性能. 因為創建一個 Match 對象可能比創建一個 String 代價要小 -- 包括產生一個 char[] 數組和復制數據, 你仍然創建了一個中間對象, 對你的調用者來說沒有價值.

  這已經足夠壞了, BadREgExpMatcher 強迫你使用它想看到的輸入形式, 而不是你可以提供的更有效的形式. 但是使用 BadRegExpMathcer 還有另一個危險, 潛在地給 MailBot的性能帶來更大的冒險: 在處理郵件頭的時候, 你開始有避免使用 String 的傾向. 但是既然你被迫創建許多 String 對象來滿足 BadRegExpMatcher, 你可能被引誘而放棄這個目標, 更加自由地使用 String. 現在, 一個組件的糟糕的設計已經影響了使用它的程序.
甚至你后來找到了一個更好的正規表達式的組件, 不需要你提供一個 String, 那時你的整個程序都會受影響.

  一個好一些的接口

  你怎樣定義 BadRegExpMatcher, 而不引起這樣的問題呢? 首先, BadRegExpMatcher 應該不規定它的輸入. 它應該可以接受它的調用者能夠有效提供的各種輸入格式. 第二, 它不應該自動給匹配結果產生一個 String; 應該返回足夠的信息, 這樣調用者如果愿意的話可以生成它. (為方便著想, 它可以提供一個方法來做這件事, 但不是必須的) 這里有一個好一些的接口:

class BetterRegExpMatcher {
 public BetterRegExpMatcher(...);
 /** Provide matchers for multiple formats of input -- String,
     character array, and subset of character array.   Return -1 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);
 /** Get the next match against the input text, if any */
 public int getNextMatch();
 /** 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();
}

  新的接口減少了調用者把輸入轉換成匹配器希望的格式這個要求. MailBot 現在可以象下面這樣調用 match():

int resultOffset = dateMatcher.match(myBuffer, thisHeaderStart,
thisHeaderEnd-thisHeaderStart);
if (resultOffset < 0) { ... }

  這就解決了不創建任何新對象的目標. 作為一個附加的獎勵, 它的接口設計風格加到了Java 的 "lots-of-simgle-methos" 設計哲學中.

  額外的對象創建給性能的確切的沖擊依賴于 matth() 所作的工作量. 你可以通過創建和計時兩個正規表達式匹配器類, 來確定一個性能差別的上限. 在 Sun JDK 1.3 中, 上面的代碼片段在 BetterRegExpMatcher 類中大約比 BadRegExpMatcher 類要快 50 倍左右. 使用一個簡單的字串匹配的實現, BetterRegExpMatcher 比相對應的 BadRegExpMatcher 要快5倍。

  交換類型

  BadRegExpMatcher 強迫 MailBot 把輸入文本從字符數組轉換成 String, 結果是造成了一些不必要的對象的創建. 更具諷刺意味的是, BadRegExpMatcher 的許多實現都立即把 String 轉換成一個字符數組, 使它容易對輸入文本進行訪問. 這樣不僅僅申請了另一齠象, 并且還意味著你做完了所有的工作, 最后的形式和開始時一樣. MailBot 和 BadRegExpMatcher都不想處理 String -- String 只是看起來象是在組件之間傳遞文本的很明顯的格式.

  在上面的 BadRegExpMatcher 例子中, String 類是作為一個交換類型的. 一個交換類型是一種不管是調用者還是被調用者都不想使用或者以它作為數據格式的一種類型, 但是兩個都能很容易地轉換它或者從它轉換. 以交換類型定義接口在保持靈活性的同時減少了接口的復雜性, 但是有時簡單性導致了高代價的性能.

  一個交換類型最典型的例子是 JDBC ResultSet 接口. 它不可能象任何本地數據庫提供的數據集一樣提供它的 ResultSet 接口, 但是 JDBC 驅動通過實現一個 ResultSet 可以很容易地把數據庫提供的本地數據表示包裝起來. 同樣, 客戶端程序也不能象這樣表示數據記錄, 但是你幾乎可以沒有困難地把 ResultSet 轉換為想要的數據表示. 在 JDBC 的例子中,你接受了這個層次的花費, 因為它帶來了標準化和跨數據庫實現的可移植性的好處. 但是,要注意交換類型帶來的性能代價.

  這完全不值得, 使用交換類型對性能的沖擊不容易度量. 如果你對上面調用 BadRegExpMatcher的代碼片段做測試的話, 它會在運行時創建 MailBot 的輸入 String; 但是, String 的產生只用來滿足 BadRegExpMatcher. 如果你想評定一個組件對程序性能的真正的沖擊, 你應該不僅僅度量它的代碼的資源使用狀況, 還有那些使用它和恢復的代碼. 這對于標準的測試工具此很難完成.

“JAVA性能設計方法是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

荔波县| 靖江市| 田阳县| 广东省| 寿阳县| 镇沅| 敦化市| 靖江市| 日土县| 洪江市| 安徽省| 临漳县| 武山县| 寿光市| 杂多县| 淮安市| 东乌| 颍上县| 岗巴县| 伊金霍洛旗| 白水县| 交口县| 宁波市| 普陀区| 贵溪市| 大余县| 常宁市| 晋宁县| 鹤壁市| 余姚市| 宁河县| 山阳县| 凤山县| 舒城县| 探索| 平昌县| 莲花县| 兴海县| 南昌县| 喀什市| 镇赉县|