java Java中是否存在内存泄漏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4987357/
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
Can there be memory leak in Java
提问by javaguy
I get this question asked many times. What is a good way to answer
我多次被问到这个问题。什么是好的回答方式
采纳答案by Stephen C
Can there be memory leak in Java?
Java 中会出现内存泄漏吗?
The answer is that it depends on what kind of memory leak you are talking about.
答案是这取决于您所谈论的内存泄漏类型。
Classic C / C++ memory leaks occur when an application neglects to free
or dispose
an object when they are done with it, and it leaks. Cyclic references are a sub-case of this where the application has difficulty knowing when to free
/ dispose
, and neglects to do it as a result. Related problems are where the application uses an object after it has been freed, or attempts to free it twice. (You could call the latter problems memory leaks, or just bugs. Either way ... )
经典的 C/C++ 内存泄漏发生在应用程序在完成时忽略free
或dispose
对象,并且它会泄漏。循环引用是这种情况的一个子案例,其中应用程序难以知道何时使用free
/ dispose
,并因此忽略了这样做。相关问题是应用程序在对象被释放后使用它,或者尝试释放它两次。(您可以将后一个问题称为内存泄漏,或者只是错误。无论哪种方式......)
Java and other (fully1) managed languages mostlydon't suffer from these problems because the GC takes care of freeing objects that are no longer reachable. (Certainly, dangling pointer and double-free problems don't exist, and cycles are not problematic as they are for C / C++ "smart pointers" and other reference count schemes.)
Java 和其他(完全1)托管语言大多不会遇到这些问题,因为 GC 负责释放不再可访问的对象。(当然,不存在悬空指针和双释放问题,循环也不会像 C/C++“智能指针”和其他引用计数方案那样有问题。)
But in some cases GC in Java will miss objects that (from the perspective of the programmer) should be garbage collected. This happens when the GC cannot figure out that an object cannot be reached:
但是在某些情况下,Java 中的 GC 会错过(从程序员的角度)应该被垃圾收集的对象。当 GC 无法确定无法访问对象时,就会发生这种情况:
- The logic / state of the program might be such that the execution paths that would use some variable cannot occur. The developer can see this as obvious, but the GC cannot be sure, and errs on the side of caution (as it is required to).
- The programmer could be wrong about it, and the GC is avoiding what might otherwise result in a dangling reference.
- 程序的逻辑/状态可能会导致使用某些变量的执行路径不会出现。开发人员可以看到这一点很明显,但 GC 不能确定,并且在谨慎方面犯了错误(这是必需的)。
- 程序员可能错了,GC 正在避免可能导致悬空引用的内容。
(Note that the causes of memory leaks in Java can be simple, or quite subtle; see @jonathan.cone's answer for some subtle ones. The last one potentially involves external resources that you shouldn'trely on the GC to deal with anyway.)
(请注意,Java 中内存泄漏的原因可能很简单,也可能非常微妙;请参阅 @jonathan.cone 对一些微妙问题的回答。最后一个可能涉及外部资源,您无论如何都不应该依赖 GC 来处理这些资源。 )
Either way, you can have a situation where unwanted objects cannot be garbage collected, and hang around tying up memory ... a memory leak.
无论哪种方式,您都可能遇到无法对不需要的对象进行垃圾收集的情况,并且会一直占用内存......内存泄漏。
Then there is the problem that a Java application or library can allocate off-heap objects via native code that need to be managed manually. If the application / library is buggy or is used incorrectly, you can get a native memory leak. (For example: Android Bitmap memory leak... noting that this problem is fixed in later versions of Android.)
然后存在一个问题,即 Java 应用程序或库可以通过需要手动管理的本机代码分配堆外对象。如果应用程序/库有问题或使用不当,您可能会出现本机内存泄漏。(例如:Android Bitmap 内存泄漏……请注意,此问题已在更高版本的 Android 中修复。)
1 - I'm alluding to a couple of things. Some managed languages allow you to write unmanaged code where you can create classic storage leaks. Some other managed languages (or more precisely language implementations) use reference counting rather than proper garbage collecting. A reference count-based storage manager needs something (i.e. the application) to break cycles ... or else storage leaks will ensue.
1 - 我在暗示几件事。某些托管语言允许您编写非托管代码,您可以在其中创建经典的存储泄漏。其他一些托管语言(或更准确的语言实现)使用引用计数而不是适当的垃圾收集。基于引用计数的存储管理器需要一些东西(即应用程序)来打破循环……否则就会发生存储泄漏。
回答by Markus Johnsson
Yes. Memory leaks can still occur even when you have a GC. For example, you might hold on to resources such as database result sets which you must close manually.
是的。即使您有 GC,内存泄漏仍然可能发生。例如,您可能会保留必须手动关闭的数据库结果集等资源。
回答by AnthonyJoeseph
Well, considering that java uses a garbage collector to collect unused objects, you can't have a dangling pointer. However, you could keep an object in scope for longer than it needs to be, which could be considered a memory leak. More on this here: http://web.archive.org/web/20120722095536/http://www.ibm.com:80/developerworks/rational/library/05/0816_GuptaPalanki/
好吧,考虑到 java 使用垃圾收集器来收集未使用的对象,你不能有一个悬空指针。但是,您可以将对象保留在范围内的时间超过它需要的时间,这可能会被视为内存泄漏。更多关于这方面的信息:http: //web.archive.org/web/20120722095536/http: //www.ibm.com: 80/developerworks/ rational/library/05/ 0816_GuptaPalanki/
Are you taking a test on this or something? Because that's at least an A+ right there.
你是在测试这个还是什么?因为那至少是 A+。
回答by jonathan.cone
The answer is a resounding yes, but this is generally a result of the programming modelrather than an indication of some defect in the JVM. This is common when frameworks have lifecycles different of that than a running JVM. Some examples are:
答案是肯定的,但这通常是编程模型的结果,而不是 JVM 中某些缺陷的迹象。当框架的生命周期与正在运行的 JVM 不同时,这很常见。一些例子是:
- Reloading a context
- Failing to dereference observers (listeners)
- Forgetting to clean up resources after you're finished using them*
* - Billions of consulting dollars have been made resolving the last one
* - 解决最后一个问题已经花费了数十亿美元
回答by Tyler
Yes, in the sense that your Java application can accumulate memory over time that the garbage collector is unable to free.
是的,从某种意义上说,您的 Java 应用程序可能会随着时间的推移积累垃圾收集器无法释放的内存。
By maintaining references to uneeded/unwanted objects they will never fall out of scope and their memory will not be claimed back.
通过维护对不需要/不需要的对象的引用,它们永远不会超出范围,它们的内存也不会被收回。
回答by dteoh
Yes it is possible.
对的,这是可能的。
In Effective Java there is an example involving a stack implemented using arrays. If your pop operations simply decrement the index value it is possible to have a memory leak. Why? Because your array still has a reference to the popped value and you still have a reference to the stack object. So the correct thing to do for this stack implementation would be to clear the reference to the popped value using an explicit null assignment at the popped array index.
在 Effective Java 中,有一个例子涉及使用数组实现的堆栈。如果您的弹出操作只是减少索引值,则可能会出现内存泄漏。为什么?因为您的数组仍然有对弹出值的引用,并且您仍然有对堆栈对象的引用。因此,对于此堆栈实现,正确的做法是在弹出的数组索引处使用显式空赋值清除对弹出值的引用。
回答by pstanton
yes, if you don't de-reference objects they will never be garbage-collected and memory usage will increase. however because of how java is designed, this is difficult to achieve whereas in some other languages this is sometimes difficult not to achieve.
是的,如果您不取消引用对象,它们将永远不会被垃圾收集并且内存使用量会增加。然而,由于 java 的设计方式,这很难实现,而在其他一些语言中,这有时很难不实现。
edit: read Amokrane's link. it's good.
编辑:阅读 Amokrane 的链接。很好。
回答by Michael Goldshteyn
The short answer:
简短的回答:
A competent JVM has no memory leaks, but more memory can be used than is needed, because not all unused objects have been garbage collected, yet. Also, Java apps themselves can hold references to objects they no longer need and this can result in a memory leak.
一个称职的 JVM 没有内存泄漏,但可以使用比需要更多的内存,因为并非所有未使用的对象都已被垃圾收集。此外,Java 应用程序本身可以保存对不再需要的对象的引用,这可能会导致内存泄漏。
回答by Trivikram
The book Effective Javagives two more reasons for "memory leaks":
《Effective Java》一书给出了“内存泄漏”的另外两个原因:
- Once you put object reference in Cacheand forget that it's there. The reference remains in cache long before becoming irrelevant. Solution is to represent cache as a WeakHashMap
- in an API where clients register callbacks and don't re-register them explicitly. Solution is to store only weak references to them.
- 一旦您将对象引用放入Cache并忘记它在那里。引用在变得不相关之前很久就保留在缓存中。解决方案是将缓存表示为WeakHashMap
- 在客户端注册回调并且不显式重新注册它们的 API 中。解决方案是仅存储对它们的弱引用。
回答by Johnny
Yes, it can be, in a context when a program mistakenly hold a reference to an object that would be never used again and therefore it's not cleaned by the GC.
是的,当程序错误地持有对一个永远不会再次使用的对象的引用并且因此它没有被 GC 清除时,它可能是。
An example to it would be forgetting to close an opened stream:
一个例子是忘记关闭一个打开的流:
class MemoryLeak {
private void startLeaking() throws IOException {
StringBuilder input = new StringBuilder();
URLConnection conn = new URL("www.example.com/file.txt").openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
while (br.readLine() != null) {
input.append(br.readLine());
}
}
public static void main(String[] args) throws IOException {
MemoryLeak ml = new MemoryLeak();
ml.startLeaking();
}
}