ALL is Well!

          敏捷是一條很長(zhǎng)的路,摸索著前進(jìn)著

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            30 隨筆 :: 23 文章 :: 71 評(píng)論 :: 0 Trackbacks

          此問(wèn)題在項(xiàng)目中被發(fā)現(xiàn),經(jīng)查看JDK源碼(JDK1.6),String類的public String substring(int beginIndex, int endIndex)的實(shí)現(xiàn)讓我很意外。

          想重現(xiàn)這個(gè)場(chǎng)景很容易,請(qǐng)看代碼。

           1import java.util.ArrayList;
           2import java.util.List;
           3
           4public class LeakTest {
           5    public static void main(Stringargs) {
           6        List<String> handler = new ArrayList<String>();
           7        for(int i = 0; i < 100000; i++{
           8            Huge h = new Huge();
           9            handler.add(h.getSubString(15));
          10        }

          11    }

          12}

          13
          14class Huge {
          15    private String str = new String(new char[100000]);
          16    public String getSubString(int begin, int end) {
          17        return str.substring(begin, end);
          18    }

          19}

          執(zhí)行此代碼結(jié)果:

          Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

           

          問(wèn)題就出在Huge類的 getSubString 方法,它調(diào)用了String類的substring方法。

          來(lái)讓我們看看 substring 類的實(shí)現(xiàn)吧,JDK源碼如下:

           1    public String substring(int beginIndex, int endIndex) {
           2    if (beginIndex < 0{
           3        throw new StringIndexOutOfBoundsException(beginIndex);
           4    }

           5    if (endIndex > count) {
           6        throw new StringIndexOutOfBoundsException(endIndex);
           7    }

           8    if (beginIndex > endIndex) {
           9        throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
          10    }

          11    return ((beginIndex == 0&& (endIndex == count)) ? this :
          12        new String(offset + beginIndex, endIndex - beginIndex, value);
          13    }

          再讓我們接下來(lái)看看 new String(offset + beginIndex, endIndex - beginIndex, value); 的實(shí)現(xiàn):


          1    // Package private constructor which shares value array for speed.
          2    String(int offset, int count, char value[]) {
          3    this.value = value;
          4    this.offset = offset;
          5    this.count = count;
          6    }


          char[] value 數(shù)組被共享了。

           

          在我們的main函數(shù)里的循環(huán)中,每循環(huán)一次后,我們希望Huge對(duì)象被回收,且釋放它占有的內(nèi)存。

          但實(shí)際上 private String str = new String(new char[100000]); 占有的內(nèi)存并不會(huì)被釋放。

          因?yàn)?我們通過(guò) Huge 類的 getSubString 方法得到的 String 對(duì)象還存在(存在于handler的列表中),

          它雖然是 length 只有 4 的對(duì)象,卻享有著 char[100000] 的空間。

           

          解決方案:

          可以修改Huge 類的 getSubString 方法如下:

          1    public String getSubString(int begin, int end) {
          2        return new String(str.substring(begin, end));
          3    }

          只要再套一個(gè)String的構(gòu)造方法即可。

           

          至于為什么,看看JDK源碼,一看便知了。這里就不貼出來(lái)了。

           

           

          唉,以后寫(xiě)代碼得多多小心啊。


          ----2010年08月27日

          本文為原創(chuàng),歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處BlogJava
          posted on 2010-09-01 12:41 李 明 閱讀(1465) 評(píng)論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 那曲县| 康乐县| 赤壁市| 宜昌市| 抚远县| 怀远县| 彭州市| 五华县| 鄄城县| 怀来县| 台东市| 惠东县| 云和县| 镇安县| 德格县| 静安区| 襄垣县| 凤凰县| 正镶白旗| 班玛县| 登封市| 博客| 郑州市| 剑川县| 泽州县| 郓城县| 四会市| 云南省| 安西县| 苏尼特右旗| 鄯善县| 育儿| 伊宁县| 两当县| 天祝| 加查县| 永顺县| 阳朔县| 三明市| 铁岭市| 革吉县|