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;
发布评论