String类中的substring方法导致内存泄漏

Ami*_*itG 13 java memory memory-leaks

据说substring String类中的方法会导致内存泄漏.这是真的吗?怎么样?有什么替代方案吗?
特别是在寻找答案,
在java中可能导致内存泄漏的所有其他事情是什么?这将有助于我在编码时保持谨慎.

Den*_*ret 28

在以前的JDK版本中,该substring方法的实现将构建一个新String对象,保持对整个char数组的引用,以避免复制它.因此,您可能无意中仅使用一个字符串保留对非常大的字符数组的引用.这是一个可能导致错误的例子.

此方法现已更改,此"泄漏"不再存在.

如果你想使用一个旧的JDK(比OpenJDK 7更新,更新6)并且你想要使用最少的字符串substring,请使用另一个字符串的构造函数:

String s2 = new String(s1.substring(0,1));
Run Code Online (Sandbox Code Playgroud)

关于你的第二个问题,关于"其他可能导致java中内存泄漏的事情",不可能以建设性的方式回答.在java标准库中没有很多实例可以很容易地保持对对象的隐藏引用.在一般情况下,请注意您构建的所有引用,可能是未清理的集合或外部资源(文件,数据库事务,本机窗口小部件等)中可能出现的最常见问题.

  • 有人可能会说旧的实现也有其优点,因为substring()是O(1)(不再是),并且如果你仍然需要原始字符串(对于长字符串),则会消耗更少的内存. (3认同)
  • 你能更具体地解决存在问题的"过去的版本"吗? (2认同)
  • 它已经与OpenJDK 7,Update 6一起消失了. (2认同)

Bri*_*new 12

substring()方法不为a分配新的字符数组String,而是简单地String现有的 char数组上生成带有窗口的a .这是一个flyweight模式的实现,并被视为一种优化.

因此,如果我有一个巨大的String(字符数组),然后创建一个子字符串,即使我垃圾收集原始字符串,原始字符数组仍然存在(尽管你认为你有一个子字符串,比如2个字符).当(例如)解析大量输入数据流(可能是XML文件)并通过以下方式提取少量文本时,通常会遇到此问题substring()

使用看似冗余的String(String str)构造函数(String构造函数采用String!)解决了这个问题,因为它分配了一个新的(可能更小的)char数组,允许原始文件被垃圾收集.

请注意,从Java 7u6开始,此行为已更改.


Pet*_*rey 8

字符串子字符串可以导致保留比预期更多的内存.因此,这不是内存泄漏,因为这个内存可以正常恢复.

最简单的解决方案是使用最新版本的Java 7,它不会这样做.由于这是Oracle唯一免费支持的版本,因此无论如何都应该考虑这样做.

因此它在Java 7更新5中被"修复".恕我直言,它不是一个简化实现的修复.获取每个子字符串的副本需要更多的工作并且可能消耗更多的内存,但它确实意味着可以少担心一件事.

在java中可能导致内存泄漏的所有其他事情是什么?

任何对象都可以清理,因此无法在C/C++术语中创建内存泄漏.你能做的就是不正确地抓住物体.一个常见的例子是忘记关闭JDBC资源等资源.这可能会导致您以您不期望的方式保留内存.


Alb*_*urg 5

在String对象中,当您调用时substring,value属性在两个字符串之间共享.

因此,如果从大字符串中获取子字符串并将其保留很长时间,则不会对大字符串进行垃圾回收.实际上,它可能导致内存泄漏.

  • 请注意,最近的Oracle JVM不再是这种情况. (2认同)