昨天看到一个blog,用一个极端例子来说明Java中的内存问题:
http://blog.xebia.com/2007/10/04/leaking-memory-in-java/
测试代码如下:
- public class TestGC {
- 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></string> subStrings = new ArrayList<string></string>();
- for (int i = 0; i <1000000; i++) {
- TestGC testGC = new TestGC();
- subStrings.add(testGC.getSubString());
- }
- }
- }
-
如果要改掉这个bug,只要改写一下getSubString的方法就好了。
- public String getSubString() {
- return new String(this.large.substring(0,2));
- }
我测试了一下,确实如此。然后我看了一下JDK1.5.0_06代码中String类
from JDK1.5.0_06, String class:
- 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);
- }
这里用到的String的构造函数是private的
- private String(int offset, int count, char value[]) {
- this.value = value;
- this.offset = offset;
- this.count = count;
- }
上面那个例子程序改写的部分其实就是增加调用public的String构造函数另外创建一个String对象,我们再来看看这个public的构造函数,已经另外一个类似上面这个private的构造函数的public构造函数:
两个public的构造函数
- public String(String original) {
- int size = original.count;
- char[] originalValue = original.value;
- char[] v;
- if (originalValue.length > size) {
-
-
-
- v = new char[size];
- System.arraycopy(originalValue, original.offset, v, 0, size);
- } else {
-
-
- v = originalValue;
- }
- this.offset = 0;
- this.count = size;
- this.value = v;
- }
-
- public String(char value[], int offset, int count) {
- if (offset < 0) {
- throw new StringIndexOutOfBoundsException(offset);
- }
- if (count < 0) {
- throw new StringIndexOutOfBoundsException(count);
- }
-
- if (offset > value.length - count) {
- throw new StringIndexOutOfBoundsException(offset + count);
- }
- char[] v = new char[count];
- System.arraycopy(value, offset, v, 0, count);
- this.offset = 0;
- this.count = count;
- this.value = v;
- }
上面这两个public的构造函数,另外创建出来的String对象和原来的String对象并不共享其char数组的。而前面那个private的构造函数没有作arraycopy,是共享char其数组的。我想JDK这个实现有待商讨,内部使用的private的构造函数中不需要copy数组,可以共享数组。但private的构造函数被public的subString方法调用后,被外部使用时,就有问题了。
以后写相关代码时要小心了!