读书人

String substring的内存泄漏分析跟优化

发布时间: 2013-08-27 10:20:47 作者: rapoo

String substring的内存泄漏分析和优化方法
本文将对String.substring方法可能产生内存泄漏的问题进行分析,并给出相应的优化方法。

String.substring内存泄漏分析

首先看一下JDK6 String.substring的源代码:



从上述的源代码可以看出,使用substring获取子字符串方法中,原有字符串的内容value(char[])将继续重用。这种方式提高了运算速度却要在内存中保留原来字符串的内容。

例如: 读取一个5000个字符的字符串,采用substring截取其中的30个字符,在这种情况下,30个字符在内存中还是使用了5000个字符。

设想一下:如果字符串更大,比如一百万个字符,而substring只需要其中的几十个,这样的情况下将会占有较多的内存空间。如果实例多需要调用的次数多,那么很容易造成内存泄漏。

请看下面的一个例子:



避免substring的优化方法

1. 创建新的字符串。


在测试代码中,采用默认VM参数的,分别调用huge.subString1(0, i), huge.subString2(0, i)和huge.subString3(0, i)运行程序,得到的结果如下:
a)采用huge.subString1(0, i)遇到OutOfMemoryError




b)采用huge.subString2(0, i)和huge.subString3(0, i)的运行正常。

采用intern()方法会有其它的影响,因为我们将使用PermGen Space. 除非VM有足够的空间,否则也会抛出OutOfMemoryError.

比如:

使用参数-XX:PermSize=1M -XX:MaxPermSize=1M
采用huge.subString3(0, i)再运行一下:



在这种情况下,只有采用huge.subString2(0, i)的方式还能正常运行,采用huge.subString1(0, i)和huge.subString3(0, i)方法都产生了OutOfMemoryError。

比较一下打印出来的循环次数,采用intern()方法运行次数比直接采用String.substring的运行次数多很多。

通过上面的例子可以得出如下几个结论:
1. String.substring存在内存泄漏的危险。
2. 采用新建字符串和String.intern()的方法可以优化直接调用String.substring。
首先选择的是新建字符串。其次才是选择通过intern()方法。intern()方法使用有其局限性。这个只有在从大字符串中截取比较小的子字符串,并且原来的字符串不需要再继续使用的场景下有较好的作用。
/** -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)); }



尽管我们使用了huge.substring截取了很小部分的子字符串,却占用了char[1000000]的内存空间。这循环体执行过程中,huge添加到了list中,垃圾回收机制并不回回收huge中的字符串。

随着实例的增多,占用的内存空间也将增多,这就是导致出现问题的原因。

目前,很多系统依然采用1.6及其以下的JDK版本,所以,使用substring时还是需要小心点的。 不过,一般情况下,这种问题很少发生。

读书人网 >编程

热点推荐