我正在查看String类的API,发现substring方法可能会导致潜在的内存泄漏,因为它与原始字符串共享相同的字符数组。
如果原始字符串很大,那么由substring返回的小字符串可能会防止Java中支持大型数组的原始字符串被垃圾回收。
有什么想法,或者是我对API的理解有误吗。
我正在查看String类的API,发现substring方法可能会导致潜在的内存泄漏,因为它与原始字符串共享相同的字符数组。
如果原始字符串很大,那么由substring返回的小字符串可能会防止Java中支持大型数组的原始字符串被垃圾回收。
有什么想法,或者是我对API的理解有误吗。
如果你从一个相当大的字符串中提取子字符串时没有进行复制(通常通过String(String)
构造函数),就存在内存泄漏的潜在可能性。
需要注意的是,这个问题自Java 7u6以来已经有所改变。 参见https://bugs.openjdk.java.net/browse/JDK-7197183。
原来关于String
对象实现享元模式的假设不再被视为有效。
请参见此答案获取更多信息。
It was the case until Java 7u6 - you would generally deal with the issue by doing:
String sub = new String(s.substring(...)); // create a new string
That effectively removes the dependency and the original string is now available for GC. This is by the way one of the only scenarios where using the string constructor makes sense.
Since Java 7u6, a new String is created and there is no memory issue any longer.
trim()
),这是非常常见的情况,您最终会复制 N-1
个字符。 - irreputabletrim()
不是一个特殊情况。实际上,str.substring().trim()
是一个非常常见的情况,它涉及到两次复制。O(1)->O(n)
是一件大事。而且,Oracle并不知道这将如何影响现有的应用程序。 - irreputable/**
* Returns a new string that is a substring of this string. The
* substring begins with the character at the specified index and
* extends to the end of this string. <p>
* Examples:
* <blockquote><pre>
* "unhappy".substring(2) returns "happy"
* "Harbison".substring(3) returns "bison"
* "emptiness".substring(9) returns "" (an empty string)
* </pre></blockquote>
*
* @param beginIndex the beginning index, inclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if
* <code>beginIndex</code> is negative or larger than the
* length of this <code>String</code> object.
*/
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}