java效能最佳化技巧二,java效能最佳化

來源:互聯網
上載者:User

java效能最佳化技巧二,java效能最佳化
之前整理過一篇java效能最佳化的部落格,連結java效能最佳化一,今天補充幾個
1. 謹慎對待Java的迴圈遍曆Java中的列表遍曆可比它看起來要麻煩多了。就以下面兩段代碼為例:A:

  • private final List<Bar> _bars;for(Bar bar : _bars) {    //Do important stuff}
  • B:
  • private final List<Bar> _bars;for(int i = 0; i < _bars.size(); i++) {Bar bar = _bars.get(i);//Do important stuff}
  • 代碼A執行的時候 會為這個抽象列表建立一個迭代器,而代碼B就直接使用 get(i) 來擷取元素,相對於代碼A省去了迭代器的開銷。
  • 實際上這裡還是需要一些權衡的。代碼A使用了迭代器,保證了在擷取元素的時候的時間複雜度是 O(1) (使用了 getNext() 和 hasNext() 方法),最終的時間複雜度為 O(n) 。但是對於代碼B,迴圈裡每次在調用 _bars.get(i) 的時候花費的時間複雜度為 O(n)  (假設這個list為一個 LinkedList),那麼最終代碼B整個迴圈的時間複雜度就是 O(n^2)  (但如果代碼B裡面的list是 ArrayList, 那 get(i) 方法的時間複雜度就是 O(1)了)。所以在決定使用哪一種遍曆的方式的時候,我們需要考慮列表的底層實現,列表的平均長度以及所使用的記憶體。如果我們需要最佳化記憶體,再加上 ArrayList 在大多數情況下尋找的時間複雜度為 O(1) ,可以選擇代碼B所使用的方法。

  • 2.在初始化的時候預估集合的大小

從Java的這篇 文檔我們可以瞭解到: “一個HashMap 執行個體有兩個影響它效能的因素:初始大小和載入因子(load factor)。 當雜湊表的大小達到初始大小和載入因子的乘積的時候,雜湊表會進行 rehash操作。如果在一個HashMap 執行個體裡面要儲存多個映射關係時,我們需要設定足夠大的初始化大小以便更有效地儲存映射關係而不是讓雜湊表自動成長讓後rehash,造成效能瓶頸。”


常常碰到需要遍曆一個 ArrayList 並將這些元素儲存到 HashMap 裡面去,將這個 HashMap 初始化預期的大小可以避免再次雜湊所帶來的開銷。初始化大小可以設定為輸入的數組大小除以預設載入因子的結果值(這裡取0.7):
  • 最佳化前的代碼:
  • HashMap<String,Foo> _map;void addObjects(List<Foo> input){  _map = new HashMap<String, Foo>();  for(Foo f: input)  {    _map.put(f.getId(), f);  }}

    最佳化後的代碼
  • HashMap<String,Foo> _map;void addObjects(List<Foo> input){_map = new HashMap<String, Foo>((int)Math.ceil(input.size() / 0.7));for(Foo f: input){_map.put(f.getId(), f);}}


  • 3. 延遲運算式的計算

在Java中,所有的方法參數會在方法調用之前,只要有方法參數是一個運算式的都會先對這個運算式進行計算(從左至右)。這個規則會導致一些不必要的操作。考慮到下面一個情境:使用ComparisonChain比較兩個 Foo 對象。使用這樣的比較鏈條的一個好處就是在比較的過程中只要一個 compareTo 方法返回了一個非零值整個比較就結束了,避免了許多無謂的比較。例如現在這個情境中的要比較的對象最先考慮他們的score, 然後是 position, 最後就是 _bar 這個屬性了:

public class Foo {private float _score;private int _position;private Bar _bar; public int compareTo (Foo other) {return ComparisonChain.start().compare(_score, other.getScore()).compare(_position, other.getPosition()).compare(_bar.toString(), other.getBar().toString()).result;}}

但是上面這種實現方式總是會先產生兩個 String 對象來儲存 bar.toString() 和other.getBar().toString() 的值,即使這兩個字串的比較可能不需要。避免這樣的開銷,可以為Bar 對象實現一個 comparator:

public class Foo {private float _score;private int _position;private Bar _bar;private final BarComparator BAR_COMPARATOR = new BarComparator(); public int compareTo (Foo other) {return ComparisonChain.start().compare(_score, other.getScore()).compare(_position, other.getPosition()).compare(_bar, other.getBar(), BAR_COMPARATOR).result();}private static class BarComparator implements Comparator<Bar> {@Overridepublic int compare(Bar a, Bar b) {return a.toString().compareTo(b.toString());}}}


4. 提前編譯Regex

字串的操作在Java中算是開銷比較大的操作。還好Java提供了一些工具讓Regex儘可能地高效。動態Regex在實踐中比較少見。在接下來要舉的例子中,每次調用 String.replaceAll() 都包含了一個常量模式應用到輸入值中去。因此我們預先編譯這個模式可以節省CPU和記憶體的開銷。

最佳化前:

  • private String transform(String term) {return outputTerm = term.replaceAll(_regex, _replacement);}

  • 最佳化後:
  • private final Pattern _pattern = Pattern.compile(_regex);private String transform(String term) {return outputTerm = _pattern.matcher(term).replaceAll(_replacement);}

5. 儘可能地緩衝Cache it if you can

將結果儲存在緩衝裡也是一個避免過多開銷的方法。現在已經有多種LRU(Least Recently Used )緩衝演算法實現。 


6. String的intern方法有用,但是也有危險

String 的 intern 特性有時候可以代替緩衝來使用。

從這篇文檔,我們可以知道:

“A pool of strings, initially empty, is maintained privately by the class String. When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned”.

這個特性跟緩衝很類似,但有一個限制,你不能設定最多可容納的元素數目。因此,如果這些intern的字串沒有限制(比如字串代表著一些唯一的id),那麼它會讓記憶體佔用飛速增長。


作者:jason0539

部落格:http://blog.csdn.net/jason0539(轉載請說明出處)

掃碼關注我公眾號

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.