編寫Java代碼製造一個記憶體溢出的情況_java

來源:互聯網
上載者:User

 這將會是一篇比較邪惡的文章,當你想在某個人的生活中製造悲劇時你可能會去google搜尋它。在Java的世界裡,記憶體溢出僅僅只是你在這種情況下可能會引入的一種bug。你的受害者會在辦公室裡度過幾天甚至是幾周的不眠之夜。

在這篇文章中我將會介紹兩種溢出方式,它們都是比較容易理解和重現的。並且它們都是來源現實項目的案例研究,但是為了讓你清晰地掌握,我把它們簡化了。

不過放心,在我們遇到和解決了很過溢出bug之後,類似的案例將會比你想象得更加普遍。

先來一個進入狀態的,在使用HashSet/HashMap時,所用索引值沒有或者其equals()/hashCode()方法不正確,這會導致一個臭名昭著的錯誤。
 

class KeylessEntry {   static class Key {   Integer id;    Key(Integer id) {     this.id = id;   }    @Override   public int hashCode() {     return id.hashCode();   }  }   public static void main(String[] args) {   Map m = new HashMap();   while (true)     for (int i = 0; i < 10000; i++)      if (!m.containsKey(i))        m.put(new Key(i), "Number:" + i);  }}

當你運行上面的代碼時,你可能會期望它運行起來永遠不會出問題,畢竟內建的緩衝方案只會增加到10,000個元素,然後就不會再增加了,所有的key都已經出現在 HashMap中。然而,事情並非如此。元素將會一直增長, 因為Key這個類沒有在hashCode()後實現一個合適的equals()方法。


解決方案很簡單,只要和下面的樣本一樣添加一個equals方法就可以了。但是在找到問題所在之前,你肯定已經花費了不少寶貴的腦細胞。
 

@Overridepublic boolean equals(Object o) {  boolean response = false;  if (o instanceof Key) {   response = (((Key)o).id).equals(this.id);  }  return response;}

下一個你得提醒朋友的是和String處理相關的操作。它的表現會很詭異,特別是結合JVM版本差異的時候。String的內部工作機制在 JDK 7u6中被改變了,所以如果你發現產品環境只是小版本號碼的區別,那麼你已經準備好條件了。把類似下面的代碼給你的朋友調試,然後問他為什麼這個bug只會在產品中出現。
 

class Stringer {  static final int MB = 1024*512;   static String createLongString(int length){   StringBuilder sb = new StringBuilder(length);   for(int i=0; i < length; i++)     sb.append('a');   sb.append(System.nanoTime());   return sb.toString();  }   public static void main(String[] args){   List substrings = new ArrayList();   for(int i=0; i< 100; i++){     String longStr = createLongString(MB);     String subStr = longStr.substring(1,10);     substrings.add(subStr);   }  }}

上面的代碼出了什麼問題呢?當它在JDK 7u6之前的版本上啟動並執行時候,返回的字串將會儲存一個對那個1M左右大小的字串的引用,如果你啟動並執行時候設定為-Xmx100m,你會得到一個意想不到的oom錯誤。結合你實驗環境中平台和版本的差異,傷腦經的事情就產生了。

現在如果你想掩蓋你的足跡,我們可以引進一些更加進階的概念。比如

  •     在不同的類載入器中載入有破壞性的代碼,在載入的類被原始類載入器刪除後保持對它的引用,可以類比一個類載入器溢出
  •     把攻擊性的程式碼後置在finalize方法中,使得程式表現變得不可預測
  •     在一個長期啟動並執行線程中加入棘手的組合,它可能在ThreadLocals中儲存了一些可以被線程池訪問的東西,以便管理應用線程。


我希望我們給了你一些思考的原材料以及當你想修理某人時的一些素材。這將帶來無窮無盡的調試。除非你的朋友使用 Plumbr來尋找溢出的所在地。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.