Java中是否存在内存泄漏

这个问题我被问了很多次。什么是回答的好方法


答案 1

Java中会有内存泄漏吗?

答案是,这取决于您正在谈论的是哪种内存泄漏。

经典的C / C++内存泄漏发生在应用程序疏忽或对象完成时,并且泄漏。循环引用是这种情况的一个子案例,其中应用程序很难知道何时/,因此忽略了这样做。相关的问题是应用程序在释放对象后使用该对象,或者尝试释放该对象两次。(您可以将后一个问题称为内存泄漏,或者只是错误。无论哪种方式... )freedisposefreedispose

Java和其他(完全1)托管语言大多不会遇到这些问题,因为GC负责释放不再可访问的对象。(当然,悬空指针和无双问题不存在,循环也没有问题,因为它们对于C / C++“智能指针”和其他参考计数方案也是如此。

但在某些情况下,Java中的GC会错过(从程序员的角度来看)应该被垃圾回收的对象。当 GC 无法确定无法到达对象时,会发生这种情况:

  • 程序的逻辑/状态可能是这样,将使用某些变量的执行路径无法出现。开发人员可以认为这是显而易见的,但GC不能确定,并且在谨慎方面犯了错误(因为它需要)。
  • 程序员可能对此是错误的,而GC正在避免可能导致悬垂的引用。

(请注意,Java中内存泄漏的原因可能很简单,也可能非常微妙;有关一些微妙的问题,请参阅@jonathan.cone的答案。最后一个可能涉及外部资源,无论如何都不应依赖 GC 来处理这些资源。

无论哪种方式,您都可能遇到不需要的对象无法被垃圾回收的情况,并四处闲逛占用内存......内存泄漏。

然后存在一个问题,即Java应用程序或库可以通过需要手动管理的本机代码分配堆外对象。如果应用程序/库有问题或使用不当,则可能会发生本机内存泄漏。(例如:安卓位图内存泄漏...请注意,此问题已在更高版本的 Android 中修复。


1 - 我指的是几件事。某些托管语言允许你编写非托管代码,在其中可以创建经典存储泄漏。其他一些托管语言(或更确切地说是语言实现)使用引用计数而不是适当的垃圾回收。基于引用计数的存储管理器需要一些东西(即应用程序)来打破周期......否则将发生存储泄漏。


答案 2

是的。即使您有 GC,仍可能发生内存泄漏。例如,您可以保留必须手动关闭的资源,如数据库结果集。