据说String类中的substring
方法会导致内存泄漏。这是真的吗?怎么样?有什么替代方案吗?
特别是寻找答案,
在java中可能导致内存泄漏的所有其他事情是什么?这将有助于我在编码时保持谨慎。
答案 0 :(得分:27)
在以前版本的JDK中,substring
方法的实现将构建一个新的String
对象,保持对整个char数组的引用,以避免复制它。因此,您可能无意中仅使用一个字符串保留对非常大的字符数组的引用。 Here's an example这可能导致的错误。
此方法现已更改,此“泄漏”不再存在。
如果你想使用一个旧的JDK(早于OpenJDK 7,Update 6)并且想要在substring
之后拥有最少的字符串,那么使用带有另一个字符串的构造函数:
String s2 = new String(s1.substring(0,1));
关于你的第二个问题,关于“java中可能导致内存泄漏的其他事情”,不可能以建设性的方式回答。在java标准库中没有很多实例可以很容易地保持对对象的隐藏引用。在一般情况下,请注意您构建的所有引用,可能是未清除的集合或外部资源(文件,数据库事务,本机窗口小部件等)中可能出现的最常见问题。
答案 1 :(得分:11)
substring()
方法不会为String
分配新的字符数组,而只是生成一个带有现有字符的窗口的String
阵列。这是一个flyweight模式的实现,并被视为一种优化。
因此,如果我有一个巨大的String
(char数组),然后创建一个子字符串,即使我垃圾收集原始字符串,原始字符数组仍然存在(尽管你认为你有一个子字符串比方说,2个字符)。当(例如)解析大量输入数据流(可能是XML文件)并通过substring()
使用看似冗余的String(String str)
构造函数(String
构造函数取String
!)解析了这个,因为它分配了一个新的(可能更小的)char数组,允许原始文件是垃圾收集。
请注意,从Java 7u6开始,此行为已更改。
答案 2 :(得分:8)
字符串子字符串可以导致保留比预期更多的内存。因此,这不是内存泄漏,因为这个内存可以正常恢复。
最简单的解决方案是使用最新版本的Java 7,但不会这样做。由于这是Oracle唯一免费支持的版本,因此无论如何都应该考虑这样做。
因此它在Java 7更新5中被“修复”。恕我直言,它不是一个简化实现的修复。获取每个子字符串的副本需要更多的工作并且可能消耗更多的内存,但这确实意味着可以少担心一件事。
java中可能导致内存泄漏的其他因素是什么?
任何对象都可以清理,因此无法在C / C ++术语中创建内存泄漏。你能做的就是不正确地抓住物体。一个常见的例子是忘记关闭JDBC资源等资源。这可能会导致您以您不期望的方式保留内存。
答案 3 :(得分:5)
在String对象中,当您调用substring
时,value
属性在两个字符串之间共享。
因此,如果从大字符串中获取子字符串并保留很长时间,那么大字符串将不会被垃圾收集。实际上,它可能会导致内存泄漏。