Java 大型子字符串的内存使用情况?

Java 大型子字符串的内存使用情况?,java,Java,读取String#substring(Java 1.7)的源代码时,它似乎重用了字符数组,但偏移量和长度不同。这意味着如果我有一个巨大的字符串作为子字符串,那么初始字符串将永远不会被GC回收(对吗?) 确保回收巨型字符串的最简单方法是什么?我正在运行JavaSE-1.7 (出于好奇,我将用Java编写一个基数实现以减少内存使用。这个问题的答案对于避免基数树使用过多的内存是至关重要的)对于JDK 7u6之前的版本 在这种情况下,您应该使用String(String)构造函数: 163 publi

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

确保回收巨型
字符串的最简单方法是什么?我正在运行JavaSE-1.7


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

对于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 }

当您将
s.substring()
的结果传递给
String
构造函数时,它将不会使用原始
字符串的
char[]
。因此原始的
字符串可以是GC。这实际上是应该使用
String
构造函数的用例之一。而在大多数情况下,我们应该使用
String
literal赋值

适用于JDK 7u6+版本


在Java7中,
String.substring()
的实现已经改变,它现在在内部使用
String(char-value[],int-offset,int-count)
构造函数(在旧版本中我们必须手动使用它以避免内存泄漏)。此构造函数检查它是否需要原始
字符串
值[]
数组,或者一个更短的数组就足够了。因此,对于JDK 7+,使用
String.substring()
不会造成内存泄漏问题。请查看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 }

当您将
s.substring()
的结果传递给
String
构造函数时,它将不会使用原始
字符串的
char[]
。因此原始的
字符串可以是GC。这实际上是应该使用
String
构造函数的用例之一。而在大多数情况下,我们应该使用
String
literal赋值

适用于JDK 7u6+版本


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

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


因此,此方法将返回一个全新的String对象,或者如果beginIndex为0,则将返回originam字符串。我想你关心的是第一个案子。在这种情况下,一旦创建了旧字符串,它就与旧字符串无关。

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



因此,此方法将返回一个全新的String对象,或者如果beginIndex为0,则将返回originam字符串。我想你关心的是第一个案子。在这种情况下,一旦创建了旧版本,它与旧版本没有任何关系。

请看以下内容。您能用您使用的Java的精确版本更新您的问题吗?Pshemo:question updated.@Ztyx如果您想让别人知道您的评论,请确保在其中添加
@nickofthaperson
。不管怎样,我问的更多的是发行号。我感兴趣的是它是在
Java1.7.006
之前还是之后,因为这种行为后来发生了变化,以避免存储原始数组,正如您所注意到的,原始数组不能被GC删除。@Pshemo我明白了。无论如何,我正在本地运行
java1.8.0_45-b14
。请看以下内容。您能用您正在使用的Java的精确版本更新您的问题吗?Pshemo:question updated.@Ztyx如果您想让别人知道您的评论,请确保在其中添加
@nickofthaperson
。不管怎样,我问的更多的是发行号。我感兴趣的是它是在
Java1.7.006
之前还是之后,因为这种行为后来发生了变化,以避免存储原始数组,正如您所注意到的,原始数组不能被GC删除。@Pshemo我明白了。无论如何,我正在本地运行
Java1.8.0_45-b14
。”下面是substring()方法的部分代码:“这段代码来自哪个版本的Java?@Pshemo,我已经更新了确切的版本。谢谢我应该提到它。那个么你们的答案是基于版本的代码,该版本已经纠正了OP提到的问题。回到过去,
新字符串(int start,int end,char[]value)
只需将
char[]value
存储在
substring
result:中,这就防止了它成为GC。从
7u06
开始的Java版本正在使用这个构造函数,它实际上复制传递的
char[]值
转换为新的较小数组,允许GC删除原始数组和较大数组。我明白了。谢谢!下面是substring()方法的部分代码:“这段代码来自哪个版本的Java?@Pshemo,我已经更新了确切的版本。谢谢我应该提到它。那个么你们的答案是基于版本的代码,该版本已经纠正了OP提到的问题。回到过去,
新字符串(int start,int end,char[]value)
只需将
char[]value
存储在
substring
result:中,这就防止了它成为GC。从
7u06
开始的Java版本正在使用这个构造函数,它实际上复制传递的
char[]值
放入新的较小数组,该数组允许GC
return ((beginIndex == 0) && (endIndex == value.length)) ? this
       : new String(value, beginIndex, subLen);