为什么要将“”添加到字符串保存内存?
我使用了一个有很多数据的变量,比如String data
。 我想用下面的方式使用这个字符串的一小部分:
this.smallpart = data.substring(12,18);
经过几个小时的调试(使用内存可视化工具)后,我发现objects field smallpart
记住了所有来自data
,尽管它只包含子字符串。
当我将代码更改为:
this.smallpart = data.substring(12,18)+"";
问题解决了! 现在我的应用程序现在使用的内存很少!
这怎么可能? 任何人都可以解释吗? 我认为this.smallpart一直在引用数据,但为什么?
更新:然后我如何清除大字符串? 将数据=新的字符串(data.substring(0,100))做的事情?
执行以下操作:
data.substring(x, y) + ""
创建一个新的(较小的)String对象,并抛出对由substring()创建的String的引用,从而启用垃圾收集。
要认识到的重要一点是, substring()
给出一个窗口到一个现有的String - 或者说,是原始String下的字符数组。 因此它将消耗与原始字符串相同的内存。 这在某些情况下可能是有利的,但是如果您想获取子字符串并处理原始字符串(如您已经发现的那样),则会出现问题。
查看JDK字符串源中的substring()方法以获取更多信息。
编辑:要回答您的补充问题,从子字符串构造一个新的字符串将减少您的内存消耗,只要您bin任何引用原始字符串。
注(2013年1月)。 上述行为在Java 7u6中发生了变化。 flyweight模式不再使用,并且substring()
将按照您的预期工作。
如果你看一下substring(int, int)
的来源substring(int, int)
,你会看到它返回:
new String(offset + beginIndex, endIndex - beginIndex, value);
其中value
是原始char[]
。 所以你得到一个新的字符串,但具有相同的底层char[]
。
当你这样做时, data.substring() + ""
,你得到一个新的字符串和一个新的基础char[]
。
实际上,您的用例是您应该使用String(String)
构造函数的唯一情况:
String tiny = new String(huge.substring(12,18));
当你使用substring
,它实际上并不创建一个新的字符串。 它仍然引用您的原始字符串,并具有偏移量和大小限制。
所以,为了让你的原始字符串被收集,你需要创建一个新的字符串(使用new String
,或者你有什么)。