Java String.substring記憶體泄露?

來源:互聯網
上載者:User

標籤:

String可以說是最常用的Java類型之一了,但是最近聽說JDK6裡面String.substring存在記憶體泄露的bug,夥驚呆!一起來看看到底是啥情況吧。

這個是可以導致Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 的代碼: 

public class TestGC {    private String largeString = new String(new byte[100000]);     String getString() {        return this.largeString.substring(0, 2);//在JDK6裡會導致out of memory,在JDK7和8不會出現問題//        return new String("ab");//        return this.largeString.substring(0,2) + "";//JDK6下的解決方案,不會出現out of memory//        return new String(this.largeString.substring(0, 2));/JDK6下的解決方案,不會出現out of memory    }     public static void main(String[] args) {        java.util.List<String> list = new java.util.ArrayList<String>();        for (int i = 0; i < 100000; i++) {            TestGC gc = new TestGC();            list.add(gc.getString());        }        System.out.println("over" + list.size());     }}

 

  但是用JDK8運行,平安無事。注意,之前看的網上文章又說安裝了JDK8,只需要在Eclipse裡面選Compiler選項為JDK6就可以了,我實 驗是不可以的,自己想想String是JDK裡面rt.jar的類,就算是編譯為JDK6的代碼,啟動並執行時候還是用的JDK8的String啊,所以無法 複現bug才是正常的。要複現,只能下載安裝JDK6.

有人認為這個會out of memory是因為TestGC對象裡面有很大largeString的對象,但是其實在調用getString方法後,TestGC對象完全可以被回收 的,largeString也可以回收,JVM的自動記憶體回收應該不會有bug吧,不然還得了!將getString方法改為直接返回一個String對 象,就可以看出,不會有問題。

現在來看看為什麼JDK6裡面,substring會導致錯誤呢。Ctrl+B(IDEA的查看源碼快速鍵點進去看下),代碼如下 

public String substring(int beginIndex, int endIndex) {    if (beginIndex < 0) {        throw new StringIndexOutOfBoundsException(beginIndex);    }    if (endIndex > count) {        throw new StringIndexOutOfBoundsException(endIndex);    }    if (beginIndex > endIndex) {        throw new StringIndexOutOfBoundsException(endIndex - beginIndex);    }    return ((beginIndex == 0) && (endIndex == count)) ? this :        new String(offset + beginIndex, endIndex - beginIndex, value);    }

 前面幾行主要是做範圍檢查,最主要的是  

new String(offset + beginIndex, endIndex - beginIndex, value);

 

String(int offset, int count, char value[]) {this.value = value;this.offset = offset;this.count = count;}

 可以看到JDK6裡的substring複用了原來大String的整個value,即String裡存放實際char的數組 

/** The value is used for character storage. */    private final char value[];

 而只是通過修改beginIndex和offset來達到複用value,避免數組copy的麻煩(以及可以提高一點效能),但是問題就是,如果原 String很大,而substring保留的時間比較久,就有可能導致整個很大的value無法回收。JDK6下的修複方法就是,強制產生一個新的 String,避免複用原來String裡的value,比如: 

return this.largeString.substring(0,2) + "";//JDK6下的解決方案,不會出現out of memory

 其實,這恰恰也是JDK8裡面的實現方式。上src:  

public String substring(int beginIndex, int endIndex) {        if (beginIndex < 0) {            throw new StringIndexOutOfBoundsException(beginIndex);        }        if (endIndex > value.length) {            throw new StringIndexOutOfBoundsException(endIndex);        }        int subLen = endIndex - beginIndex;        if (subLen < 0) {            throw new StringIndexOutOfBoundsException(subLen);        }        return ((beginIndex == 0) && (endIndex == value.length)) ? this                : new String(value, beginIndex, subLen);    }

 跟前面區別不大,再來看  

public String(char value[], int offset, int count) {        if (offset < 0) {            throw new StringIndexOutOfBoundsException(offset);        }        if (count < 0) {            throw new StringIndexOutOfBoundsException(count);        }        // Note: offset or count might be near -1>>>1.        if (offset > value.length - count) {            throw new StringIndexOutOfBoundsException(offset + count);        }        this.value = Arrays.copyOfRange(value, offset, offset+count);    }

 可以看到,最後對value做了數組copy。

其實JDK8的修改也是褒貶不一,也有人認為JDK6裡面的實現方法更好,效率更高,只要自己注意就可以避免問題的,這就是仁者見仁智者見智的問題了,只是需要知道,JDK6裡String的這個小坑就好。

參考文章

  1. http://droidyue.com/blog/2014/12/14/substring-memory-issue-in-java/

  2. http://www.programcreek.com/2013/09/the-substring-method-in-jdk-6-and-jdk-7/


Java String.substring記憶體泄露?

聯繫我們

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