在 Java 7, Update 6 之前,substring 方法会有内存泄漏的问题。
substring 会构造一个新的 string 对象,该 string 对象引用了原来的 string 对象的一个 char 数组。这会导致原有的 string 对象不会被垃圾回收。引发内存泄漏。
看源码:
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);
}
上面调用的构造方法如下:
//Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
其中传入的 value 用的还是原来 string 对象的 value。即这个 value 的值会被两个 string 对象共享着。(String 类中的私有成员:private final char value[]; )
内存模型如下:
可以用如下代码规避:
String sub = new String(s.substring(…)); // create a new string
或者用更新版本的 JDK,在 JDK7 中,这个 value 值的赋值方式为:
this.value = Arrays.copyOfRange(value, offset, offset + count);
也不会有内存泄漏的问题。