String substring的内存泄漏分析和优化方法
- - ITeye博客本文将对String.substring方法可能产生内存泄漏的问题进行分析,并给出相应的优化方法. String.substring内存泄漏分析. 首先看一下JDK6 String.substring的源代码:. 从上述的源代码可以看出,使用substring获取子字符串方法中,原有字符串的内容value(char[])将继续重用.
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[];
/**
* 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) {
return substring(beginIndex, count);
}
/**
* Returns a new string that is a substring of this string. The
* substring begins at the specified <code>beginIndex</code> and
* extends to the character at index <code>endIndex - 1</code>.
* Thus the length of the substring is <code>endIndex-beginIndex</code>.
* <p>
* Examples:
* <blockquote><pre>
* "hamburger".substring(4, 8) returns "urge"
* "smiles".substring(1, 5) returns "mile"
* </pre></blockquote>
*
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if the
* <code>beginIndex</code> is negative, or
* <code>endIndex</code> is larger than the length of
* this <code>String</code> object, or
* <code>beginIndex</code> is larger than
* <code>endIndex</code>.
*/
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 my.memoryLeak;
import java.util.ArrayList;
import java.util.List;
public class MemoryLeakExample {
public static void main(String[] args) {
/** -XX:PermSize=1M -XX:MaxPermSize=1M */
List<String> substringList = new ArrayList<String>();
/**
* 循环3000次。
* 第i次循环截取前i个字符串
*/
for (int i = 1; i <= 3000; i++) {
HugeString huge = new HugeString();
System.out.println(i);
substringList.add(huge.subString1(0, i));
}
}
}
class HugeString {
private String str = new String(new char[1000000]);
/**
* 调用String的subString方法来实现。
* 例如: 读取一个5000个字符的字符串,采用substring截取其中的30个字符,在这种情况下,30个字符在内存中还是使用了5000个字符。
* 设想一下:如果字符串更大,比如一百万个字符,而substring只需要其中的几十个,
* 这样的情况下会将会占有较多的内存空间。如果实例多需要调用的次数多,那么很容易造成内存泄漏。
* Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
* at java.util.Arrays.copyOf(Unknown Source)
* at java.lang.String.<init>(Unknown Source)
* at my.memoryLeak.Huge.<init>(LeakTest.java:38)
* at my.memoryLeak.MemoryLeakExample.main(MemoryLeakExample.java:13)
*
*/
public String subString1(int begin, int end) {
return str.substring(begin, end);
}
/**
* 采用新建的方式,避免在内存中占有较多的内容。
*/
public String subString2(int begin, int end) {
return new String(str.substring(begin, end));
}
/**
* 将substring的内容存放到常量池。
* 这种情况下,会用到PermGen space,如果过度使用,可能导致PermGen Sapce用完,跑出异常。
*
* 可以使用如下参数调整大小,如
* -XX:PermSize=1M -XX:MaxPermSize=1M
*
* Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
* at java.lang.String.intern(Native Method)
* at my.memoryLeak.HugeString.subString3(MemoryLeakExample.java:55)
* at my.memoryLeak.MemoryLeakExample.main(MemoryLeakExample.java:15)
*/
public String subString3(int begin, int end) {
return str.substring(begin, end).intern();
}
}
/**
* 采用新建的方式,避免在内存中占有较多的内容。
*/
public String subString2(int begin, int end) {
return new String(str.substring(begin, end));
}
/**
* 将substring的内容存放到常量池。
* 这种情况下,会用到PermGen space,如果过度使用,可能导致PermGen Sapce用完,跑出异常。
*
* 可以使用如下参数调整大小,如
* -XX:PermSize=1M -XX:MaxPermSize=1M
*
* Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
* at java.lang.String.intern(Native Method)
* at my.memoryLeak.HugeString.subString3(MemoryLeakExample.java:55)
* at my.memoryLeak.MemoryLeakExample.main(MemoryLeakExample.java:15)
*/
public String subString3(int begin, int end) {
return str.substring(begin, end).intern();
}