Java中由substring方法引发的内存泄漏(2)

这段简单的程序有两个字符串变量str、sub。sub字符串是由父字符串str截取得到的,假如上述这段程序在JDK1.6中运行,我们知道数组的内存空间分配是在堆上进行的,那么sub和str的内部char数组value是公用了同一个,也就是上述有字符a~字符t组成的char数组,str和sub唯一的差别就是在数组中其实beginIndex和字符长度count的不同。在第三句,我们使str引用为空,本意是释放str占用的空间,但是这个时候,GC是无法回收这个大的char数组的,因为还在被sub字符串内部引用着,虽然sub只截取这个大数组的一小部分。当str是一个非常大字符串的时候,这种浪费是非常明显的,甚至会带来性能问题,解决这个问题可以是通过以下的方法:

String str = "abcdefghijklmnopqrst"

String sub = str.substring(13) + ""

str = null

String str = "abcdefghijklmnopqrst"; String sub = str.substring(1, 3) + ""; str = null;

利用的就是字符串的拼接技术,它会创建一个新的字符串,这个新的字符串会使用一个新的内部char数组存储自己实际需要的字符,这样父数组的char数组就不会被其他引用,令str=null,在下一次GC回收的时候会回收整个str占用的空间。但是这样书写很明显是不好看的,所以在JDK7中,substring 被重新实现了。

JDK7中的substring实现

在JDK7中改进了substring的实现,它实际是为截取的子字符串在堆中创建了一个新的char数组用于保存子字符串的字符。下面的这张图说明了JDK7中substring的实现过程:

Java中由substring方法引发的内存泄漏

 

查看JDK7中String类的substring方法的实现源码:

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); 

        } 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/17adb84fa6fd743ac7ca88313bca4367.html