String 导致的内存溢出

String是java中经常使用的类,如果使用不当,也有可能出现内存泄露。例如执行以下代码就可能出现内存不够:

public class Test {
	private String large = new String(new char[100000]);

	public String getSubString() {
		return this.large.substring(0, 2);
	}

	public static void main(String[] args) {
		ArrayList<String> subStrings = new ArrayList<String>();
		for (int i = 0; i < 1000000; i++) {
			Test test = new Test();
			subStrings.add(test.getSubString());
		}
	}
}

 

我在机器上执行后出现以下错误:

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 com.bond.test.Test.<init>(Test.java:6)
    at com.bond.test.Test.main(Test.java:17)

 

这是为什么呢? subStrings 不是保存了1000000个长度为2的字符串吗,一个字符2个字节,总共不过40M 怎么会内存不够呢。其实不是这样的。

 

我们来看String中的subString方法:

 

public String substring (int start, int end) {
	if (start == 0 && end == count)
		return this;
	// NOTE last character not copied!
	// Fast range check.
	if (0 <= start && start <= end && end <= count) {
		return new String (offset + start, end - start, value);
	}
	throw new StringIndexOutOfBoundsException();
}

String (int start, int length, char[] data) {
	value = data;
	offset = start;
	count = length;
}

 

我们可以看到subString返回的String与原来的String实例共享同一个value,它们引用的同一个char数组。我们可以从下面代码得到答案:

 

		 String str1 = "sldkfknkldbjongekgds";
		 String str2 = str1.substring(3, 10);
		 Class c1 = str1.getClass();
		 Field f1 = c1.getDeclaredField("value");
		 f1.setAccessible(true);
		
		 Class c2 = str2.getClass();
		 Field f2 = c2.getDeclaredField("value");
		 f2.setAccessible(true);
		 System.out.println(f1.get(str1)==f2.get(str2));
		 System.out.println(Arrays.toString(((char[])(f2.get(str1)))));

 

结果:

true
[s, l, d, k, f, k, n, k, l, d, b, j, o, n, g, e, k, g, d, s]

可见虽然str2的长度为7,但是实际大小却和str1一样。

这个问题的解决办法就是new String(str.subString(int));来替代直接用subString 方法得到String实例:

public String getSubString() {
    return new String(this.large.substring(0,2));
  }

 这样创建的String的实际大小就只有2了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值