内存使用大的子串?

时间:2015-05-21 10:28:34

标签: java

阅读String#substring(Java 1.7)的源代码,看起来它重用了字符数组,但具有不同的偏移量和长度。这意味着,如果我有一个巨型的String,我将子串起来,GC的初始字符串将永远不会被回收(对吧?)。

确定巨型String被收回的最简单方法是什么?我正在运行JavaSE-1.7。

(好奇的是,我将用Java编写基数实现以减少内存使用。这个问题的答案对于避免基数树使用的内存超过必要而非常重要。

2 个答案:

答案 0 :(得分:4)

适用于JDK 7u6之前的版本

在这种情况下你应该使用String(String)构造函数:

163  public String(String original) {
164 int size = original.count;
165 char[] originalValue = original.value;
166 char[] v;
167 if (originalValue.length > size) {
168 // The array representing the String is bigger than the new
169 // String itself. Perhaps this constructor is being called
170 // in order to trim the baggage, so make a copy of the array.
171 int off = original.offset;
172 v = Arrays.copyOfRange(originalValue, off, off+size);
173 } else {
174 // The array representing the String is the same
175 // size as the String, so no point in making a copy.
176 v = originalValue;
177 }
178 this.offset = 0;
179 this.count = size;
180 this.value = v;
181 }

String s = "some really looooong text";
String s2 = new String(s.substring(0,3));

当您将s.substring()的结果传递给String构造函数时,它将不会使用原始char[]的{​​{1}}。所以原来的String可以是GC。这实际上是应该使用String构造函数的用例之一。虽然在大多数情况下我们应该使用String文字作业。

对于JDK 7u6 +版本

在Java 7中,String的实现已经改变,现在内部使用String.substring()构造函数(我们必须在旧版本中手动使用以避免内存泄漏)。此构造函数检查它是否需要原始String(char value[], int offset, int count)的{​​{1}}数组,否则较短的数组就足够了。因此对于使用String的JDK 7+不会造成内存泄漏问题。请查看源代码String.substring()

答案 1 :(得分:0)

如果需要,原始字符串将始终为垃圾收集。没人会反对。以下是substring()方法的部分代码(JDK 1.7.0_51):

return ((beginIndex == 0) && (endIndex == value.length)) ? this
       : new String(value, beginIndex, subLen);

因此,此方法返回一个全新的String对象,或者如果beginIndex为0,则返回原始String。我想你担心第一个案子。在这种情况下,它与旧版本创建后无关。