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

Java中我们无须关心内存的释放,JVM提供了内存管理机制,有垃圾回收器帮助回收不需要的对象。但实际中一些不当的使用仍然会导致一系列的内存问题,常见的就是内存泄漏和内存溢出

内存溢出(out of memory ):通俗的说就是内存不够用了,比如在一个无限循环中不断创建一个大的对象,很快就会引发内存溢出。

内存泄漏(leak of memory):是指为一个对象分配内存之后,在对象已经不在使用时未及时的释放,导致一直占据内存单元,使实际可用内存减少,就好像内存泄漏了一样。 

由substring方法引发的内存泄漏

substring(int beginIndex, int endndex )是String类的一个方法,但是这个方法在JDK6和JDK7中的实现是完全不同的(虽然它们都达到了同样的效果)。了解它们实现细节上的差异,能够更好的帮助你使用它们,因为在JDK1.6中不当使用substring会导致严重的内存泄漏问题。

1、substring的作用

substring(int beginIndex, int endIndex)方法返回一个子字符串,从父字符串的beginIndex开始,结束于endindex-1。父字符串的下标从0开始,子字符串包含beginIndex而不包含endIndex。

String x= "abcdef"

x= str.substring(1,3); 

System.out.println(x); 

String x= "abcdef"; x= str.substring(1,3); System.out.println(x);

上述程序的输出是“bc” 

2、实现原理

String类是不可变变,当上述第二句中x被重新赋值的时候,它会指向一个新的字符串对象,就像下面的这幅图所示:

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

然而,这幅图并没有准确说明的或者代表堆中发生的实际情况,当substring被调用的时候真正发生的才是这两者的差别。

JDK6中的substring实现

String对象被当作一个char数组来存储,在String类中有3个域:char[] value、int offset、int count,分别用来存储真实的字符数组,数组的起始位置,String的字符数。由这3个变量就可以决定一个字符串。当substring方法被调用的时候,它会创建一个新的字符串,但是上述的char数组value仍然会使用原来父数组的那个value。父数组和子数组的唯一差别就是count和offset的值不一样,下面这张图可以很形象的说明上述过程。

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

看一下JDK6中substring的实现源码:

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); //使用的是和父字符串同一个char数组value  

    } 

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); //使用的是和父字符串同一个char数组value }

 

String(int offset, int count, char value[]) { 

    this.value = value; 

    this.offset = offset; 

    this.count = count; 

    } 

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


由此引发的内存泄漏泄漏情况:

String str = "abcdefghijklmnopqrst"

String sub = str.substring(13); 

str = null

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

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

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