java - JDK6中String的subString方法内存泄露及溢出问题
怪我咯
怪我咯 2017-04-18 10:32:32
0
4
591

JDK6中的subString方法会存在内存泄露问题,是由于源字符串中的value数组不会被GC回收。
看到一篇文章(http://www.cnblogs.com/hxy520...),里面有如下代码,说在JDK6下会报内存溢出的错误。请问下,为什么会产生?list的每次add不是只加一点点内存占用么?

public class SubMain {

  private String strs = new String(new byte[100000]);

  String getString() {
    return this.strs.substring(0, 2);
  }

  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    SubMain sub = new SubMain();
    for (int i = 0; i < 1000000; i++) {
      list.add(sub.getString());
    }
  }

}

/*Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.lang.StringCoding$StringDecoder.decode(StringCoding.java:133)
    at java.lang.StringCoding.decode(StringCoding.java:173)
    at java.lang.StringCoding.decode(StringCoding.java:185)
    at java.lang.String.<init>(String.java:570)
    at java.lang.String.<init>(String.java:593)
    at com.jd.o2o.substring.SubMain.<init>(SubMain.java:8)
    at com.jd.o2o.substring.SubMain.main(SubMain.java:18)*/

其他参考文章:http://blog.csdn.net/longzuyu...,
http://www.wtoutiao.com/p/jfc...

怪我咯
怪我咯

走同样的路,发现不同的人生

全部回覆(4)
小葫芦

前面的童鞋也講的很明白了,即使是jdk1.6的方式也不會存在你所說的內存洩漏問題。
導致你記憶體不足的原因是因為你本身就沒有足夠的記憶體申請1000000new String(new byte[100000])物件。


還有,按照你的邏輯來實現的話,JDK1.6的实现方式绝对是占用更少内存的,因为array是引用类型。即便你循环1000000substring,在String对象中的char[] value也是同一个对象,而JDK1.7使用Arrays.copy的方式实现,那你每一次substring就将会生成一个新的char[] value實例。

阿神

你需要先把java SubMain sub = new SubMain();提到for循環外面初始化。
因為你每次for循環都在堆上創建SubMain,每個SubMain都至少佔用了100k,你重複1000000次,這得需要100G的堆空間。同時list裡面保存了SubMain的引用,gc和full gc都無法回收,一定會記憶體溢出!

同時,討論記憶體分配,至少要把虛擬機器配置的-Xms,-Xmx, -Xmn, -XX:SurvivorRatio提供出來啊!

刘奇

這個問題蠻有意思,我特意查了一下, 學習了,樓主的理解是subString最多導致原來的string內存沒被回收,list的循環最多也就每次增加一點點內存。後來我仔細看了下程序:

public class SubMain {
  private String strs = new String(new byte[100000]);
  String getString() {
    return this.strs.substring(0, 2);
  }

  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    for (int i = 0; i < 1000000; i++) {
      SubMain sub = new SubMain();
      list.add(sub.getString());
    }
  }
} 

因為strings是SubMain的實例變量,而SubMain又被循環實例化了1000000次,結果可想而知...

另外, 這個問題再JDK7 update6已經被修復了。
如果是舊版JDK,可以用這樣的方式:

String s2 = new String(s1.substring(0,2));
迷茫

死勁的往堆內存中放數據 list一直保留堆內存的引用 肯定gc不回收嘍 你的內存必須溢出

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!