【问题标题】:Memory usage of a large substring?大子字符串的内存使用情况?
【发布时间】:2015-05-22 17:55:29
【问题描述】:

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

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

(出于好奇,我将在 Java 中编写一个基数实现以减少内存使用。这个问题的答案对于避免基数树使用过多的内存至关重要)

【问题讨论】:

  • 你能用你正在使用的 Java 的精确版本更新你的问题吗?
  • Pshemo:问题已更新。
  • @Ztyx 如果您希望有人收到有关您的评论的通知,请确保在其中添加 @nickOfThatPerson。无论如何,我要问的是更多关于版本号的问题。我很感兴趣它是在Java 1.7.0_06 之前还是之后,因为这种行为发生了变化,以避免存储原始数组,正如您注意到的那样,GC 无法删除该数组。
  • @Pshemo 我明白了。无论如何,我在本地运行Java 1.8.0_45-b14

标签: java


【解决方案1】:

适用于 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 // 表示字符串的数组比新的大
169 // 字符串本身。也许这个构造函数被调用了
170 // 为了减少包袱,所以复制一个数组。
171 int off = original.offset;172 v = Arrays.copyOfRange(originalValue, off, off+size);
173 } else {
174 // 数组表示字符串与字符串相同
175 // 大小与字符串相同,因此复制没有意义。
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 构造函数时,它不会使用原始Stringchar[]。所以原来的String可以是GC。这实际上是应该使用 String 构造函数的用例之一。而在大多数情况下,我们应该使用 String 文字赋值。

适用于 JDK 7u6+ 版本

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

【讨论】:

【解决方案2】:

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

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

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

【讨论】:

猜你喜欢
  • 2019-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-11
  • 1970-01-01
  • 2010-10-19
相关资源
最近更新 更多