2024年3月26日发(作者:)

String中的subString方法的内存泄露问题

(1) What’s the problem?

String的subString()会产生内存泄露。

(2) What’s the root cause?

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

}

问题就在最后一句:new String(offset + beginIndex, endIndex - beginIndex, value)

从String的构造函数源码看:

// Package private constructor which shares value array for speed.

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

{

= value; //还是原值

= offset;

= count;

}

从这里看出,subString并不是构造一个新的String对象,而是重用了原先对象的char[],通

过修改了初始偏移量和有效字符数来达到重用的目的。(这样的好处是可以避免内存拷贝,加快

速度)

但是其实subString出来的子对象,仍然是原对象的一个引用。

private void testString()

{

}

String A = new String("hello, world");

String B = ing(2,4);

如图:

此时,当A不再使用的,由于B仍然指向了该内存空间,导致h等红色空间并不能被系统马上回

收;当B长期被占用,并且被引用多次的时候,内存空间就回收的越慢。

Ah

e

l

.

.

B

(3)

What’s the solution?

使用String的构造函数

String(String original)

/** Initializes a newly created {@code String} object so that it

represents the same sequence of characters as the argument; in other

words, the newly created string is a copy of the argument string. Unl

ess an explicit copy of {@code original} is needed, use of this const

ructor is unnecessary since Strings are immutable.

*/

public String(String original)

{

int size = ;

char[] originalValue = ;

char[] v;

if ( > size)

{

// The array representing the String is bigger than the new

// String itself. Perhaps this constructor is being called

// in order to trim the baggage, so make a copy of the array.

int off = ;

v = Range(originalValue, off, off+size);

}

else

{

// The array representing the String is the same

// size as the String, so no point in making a copy.

v = originalValue;