博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java String.substring内存泄露?
阅读量:6501 次
发布时间:2019-06-24

本文共 3606 字,大约阅读时间需要 12 分钟。

hot3.png

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
 list = new java.util.ArrayList
();        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的这个小坑就好。

参考文章

转载于:https://my.oschina.net/magicly007/blog/497227

你可能感兴趣的文章
顶部滑动下拉广告
查看>>
简化代码的微小修改
查看>>
python之CSV文件格式
查看>>
你必须知道的.net学习总结
查看>>
leetcode之Reorder List
查看>>
Axure8.0 网页 or App 鼠标滚动效果
查看>>
文件操作示例脚本 tcl
查看>>
大家好,新年快乐。
查看>>
prototype
查看>>
Android学习路线
查看>>
Linux下的redis的持久化,主从同步及哨兵
查看>>
在相同的主机上创建一个duplicate数据库
查看>>
Date15
查看>>
从Date类型转为中文字符串
查看>>
基于multisim的fm调制解调_苹果开始自研蜂窝网调制解调器 最快2024年能用上?
查看>>
mupdf不支持x64_Window权限维持(七):安全支持提供者
查看>>
cf修改游戏客户端是什么意思_瓦罗兰特很有可能取代cf成为国内最火的fps游戏...
查看>>
proto文件支持继承吗_JavaScript继承(一)——原型链
查看>>
labview如何弹出提示窗口_LabVIEW开发者必读的问答汇总,搞定疑难杂症全靠它了!...
查看>>
提取series中的数值_Python中None和numpy.nan的区别
查看>>