java String类中的substring方法导致内存泄漏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15612157/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
substring method in String class causes memory leak
提问by AmitG
It is said that substring
method in String class causes memory leak. Is it true? How? What is an alternative for it?
Especially looking for answer,
What are all other things which can causes of memory leak in java? This will help me to take care while coding.
据说substring
String类中的方法会导致内存泄漏。这是真的吗?如何?什么是它的替代品?
特别是在寻找答案,
还有哪些其他因素会导致 java 中的内存泄漏?这将帮助我在编码时注意。
回答by Denys Séguret
In past versions of the JDK, the implementation of the substring
method would build a new String
object keeping a reference to the whole char array, to avoid copying it. You could thus inadvertently keep a reference to a very big character array with just a one character string. Here's an exampleof a bug this could induce.
在过去的 JDK 版本中,该substring
方法的实现将构建一个新String
对象,保留对整个 char 数组的引用,以避免复制它。因此,您可能会不经意地使用一个字符串来保留对一个非常大的字符数组的引用。这是一个可能导致的错误示例。
This method has now been changed and this "leak" doesn't exist anymore.
这种方法现在已经改变,这种“泄漏”不再存在。
If you want to use an old JDK (that is older than OpenJDK 7, Update 6) and you want to have minimal strings after substring
, use the constructor taking another string :
如果您想使用旧的 JDK(比 OpenJDK 7,Update 6 更旧)并且您想在 之后substring
使用最少的字符串,请使用带有另一个字符串的构造函数:
String s2 = new String(s1.substring(0,1));
As for your second question, regarding " other things which can causes of memory leak in java", it's impossible to answer in a constructive way. There aren't in java standard libs many instances of cases where you could so easily keep hidden references to objects. In the general case, pay attention to all the references you build, the most frequent problems probably arising in uncleaned collections or external resources (files, database transactions, native widgets, etc.).
至于你的第二个问题,关于“其他可能导致java内存泄漏的事情”,无法以建设性的方式回答。在 Java 标准库中,没有许多案例可以轻松地保留对对象的隐藏引用。在一般情况下,请注意您构建的所有引用,最常见的问题可能出现在未清理的集合或外部资源(文件、数据库事务、本机小部件等)中。
回答by Brian Agnew
The substring()
method doesn't allocate a new character array for a String
, but rather simply produces a String
with a window onto the existingchar array. This is an impementation of a flyweight pattern and was regarded as an optimisation.
该substring()
方法不会为 a 分配一个新的字符数组String
,而是简单地String
在现有的char 数组上生成一个带有窗口的 a 。这是对享元模式的一种实现,被认为是一种优化。
So if I have a huge String
(char array) and then create a substring, even if I garbage collect the original string, the original char array remains (despite the fact that you think you have a substring of, say, 2 chars). This problem is often encountered when (say) parsing a huge stream of input data (perhaps an XML file) and extracting a small amount of text via substring()
因此,如果我有一个巨大的String
(字符数组)然后创建一个子字符串,即使我对原始字符串进行垃圾收集,原始字符数组也会保留(尽管您认为您有一个子字符串,例如 2 个字符)。当(例如)解析大量输入数据(可能是 XML 文件)并通过以下方式提取少量文本时,经常会遇到此问题substring()
Using the seemingly redundant String(String str)
constructor (a String
constructor taking a String
!) resolves this since it allocates a new (potentially smaller) char array, allowing the original to be garbage collected.
使用看似多余的String(String str)
构造函数(一个String
带有String
!的构造函数)解决了这个问题,因为它分配了一个新的(可能更小的)char 数组,允许原始数组被垃圾收集。
Note this behaviour has changed as of Java 7u6.
请注意,此行为自 Java 7u6 起已更改。
回答by Peter Lawrey
String substring can result in retaining more memory than you might expect. As such it's not a memory leak as this memory can be recovered normally.
字符串子字符串可能会导致保留比您预期更多的内存。因此,这不是内存泄漏,因为该内存可以正常恢复。
The simplest solution is to use a recent version of Java 7, which doesn't do this. As this is the only freely supported version from Oracle, you should consider doing this anyway.
最简单的解决方案是使用最新版本的 Java 7,它没有这样做。由于这是 Oracle 唯一免费支持的版本,因此无论如何您都应该考虑这样做。
As such it was "fixed" in Java 7 update 5. IMHO it is not so much a fix as a simplification of the implementation. Taking a copy of every substring takes much more work and is likely to consume more memory, but it does mean there is one less thing to worry about.
因此,它在 Java 7 更新 5 中被“修复”。恕我直言,它与其说是修复,不如说是实现的简化。获取每个子字符串的副本需要更多的工作,并且可能会消耗更多的内存,但这确实意味着少了一件需要担心的事情。
What are all other things which can causes of memory leak in java?
什么是其他可能导致 Java 内存泄漏的事情?
Any object can be cleaned up as such it's not possible to create a memory leak in the C/C++ sense of the term. What you can do is hold onto objects incorrectly. A common example of this is forgetting to close resources like JDBC resource. This can cause you to retain memory in ways you don't expect.
任何对象都可以被清理,因此不可能在 C/C++ 术语的意义上创建内存泄漏。你能做的就是错误地抓住物体。一个常见的例子是忘记关闭像 JDBC 资源这样的资源。这可能会导致您以意想不到的方式保留内存。
回答by Alban Dericbourg
In the String object, when you call substring
, the value
property is shared between the two strings.
在 String 对象中,当您调用 时substring
,value
属性在两个字符串之间共享。
So, if you get a substring from a big string and keep it for a long time, the big string won't be garbage collected. It could result in a memory leak, actually.
所以,如果你从一个大字符串中得到一个子字符串并保留它很长时间,大字符串就不会被垃圾收集。实际上,它可能会导致内存泄漏。