【问题标题】:Memory leaks always need a long-lived object?内存泄漏总是需要一个长寿命的对象?
【发布时间】:2009-09-11 21:06:41
【问题描述】:

这个陈述是真的、假的还是表述不当:

“在 Java 中,内存泄漏必须始终以某种方式与长期存在的对象相关联。”

在此上下文中,我仅指常规对象,而不是一般的系统资源(文件描述符等)。

一个长寿命对象的例子可能是一个单例(无论如何通常都是这样实现的),只要应用程序正在运行,它就会一直存在。

【问题讨论】:

  • 单例本身不会导致内存泄漏,因为它只有一个实例。正如 Pyrolistical 所说,内存泄漏是错误地变成长期存在的短期对象。

标签: java memory-leaks


【解决方案1】:

误导。

虽然该陈述在技术上是正确的,但内存泄漏是由比预期寿命更长的对象引起的。

【讨论】:

  • +1 以获得简洁的答案。在纯逻辑意义上,对于对“技术”的反常理解,技术上是正确的。
  • 问题中的关键词是“相关”。问题不是长寿对象是否是泄漏的原因,而是它是否与泄漏的存在有关。不同的想法。
【解决方案2】:

该陈述是正确的,但恕我直言,表述不当。对象在不再需要后仍被引用会导致内存泄漏。

我能想到的唯一其他内存泄漏原因是 Java 应用程序未能释放 JNI 本机库中的资源。

有趣的文章here

【讨论】:

    【解决方案3】:

    “在 Java 中,内存泄漏必须始终以某种方式与长期存在的对象相关。”

    一个长寿命的对象是一个单例,或者只要应用程序运行就会一直存在的东西。

    我们可以稍微改变一下陈述,并以问题的形式表达出来。你可以问:

    Java 应用程序中是否可能存在与 Singleton 或其他核心组件无关的内存泄漏(设计为长期存在的)?

    正如我们所知道的,这里的许多人已经指出,Java 上下文中的内存泄漏本质上是剩余的无意强引用的对象,导致垃圾收集器无法使用它们。

    为了回答我们的新问题,我们需要想象一个场景,其中我们有一对对象,通常在它们移出范围后会被垃圾回收,但创建了一个循环引用(两个或多个对象彼此有很强的引用)。这里将对这些对象进行强引用,并且由于它们都超出了范围,因此它们不再与任何“长寿命”对象相关联。它们会被视为泄密吗?

    为了回答这个问题,kdgregory 在他的博客中发表了一篇题为“Java Reference Objects or 'How I Learned to Stop Worrying and Love OutOfMemoryError'”的文章:

    你可能想知道如果你有一个循环引用会发生什么:对象 A 包含对对象 B 的引用,其中包含对 A 的引用。答案是标记清除收集器不会被愚弄:如果 A 都没有B 也不能通过强引用链到达,那么它们就有资格被收集。

    【讨论】:

      【解决方案4】:

      内存泄漏也可能是由在 Java 内存模型之外分配内存并且不释放内存的短期 Java 对象引起的。 Java 进程不会泄漏此内存,但仍可能导致您耗尽系统资源。

      因此,请务必检查您的 Java 程序还调用了哪些其他进程/程序。

      【讨论】:

        【解决方案5】:

        取决于 long-lived 的规范,以及 JRE 错误的包含/排除,以及 memory-leak 的含义(只有一半的应用程序 livetime 的 memory-leaks 是什么?),以及一些垃圾收集器的特殊情况(G1应该改善的情况)等等等等……

        好吧,没有进一步上下文的问题表述得不好,但是,与 Pyrolistical 相反,我倾向于说它在技术上是错误的,至于内存泄漏的任何实际定义,我认为与你描述的这些长寿对象没有任何关系他们。

        当然,可以说没有堆栈上的一些引用,这最终取决于 main 的执行时间,或者某处的其他一些根引用,什么都不存在;但是有了这样的语义,这个问题就变得毫无意义了。这就像说没有计算机我无法运行 Java 应用程序。万岁,赢了 0 美元的价格。

        【讨论】:

          【解决方案6】:

          首先要建立一些东西:

          • 对象是从其他对象引用的,整个运行程序可以可视化为对象引用其他对象的图。
          • 根据定义,如果对象无法被活动线程访问,则可以对其进行垃圾回收。
          • 可以有意或无意地创建一个应用程序,该应用程序反复创建对象,然后从不让这些对象被垃圾回收。在长时间运行的程序中反复执行此操作,您会发现明显的内存泄漏。

          您可能对“长时间运行”、“显着”和“重复”有不同的值,但我们的想法是内存泄漏是最后一点。因此,如果您说内存泄漏与长期存在的对象相关联,那么我说这是误导 - 对象占用内存,所以它们当然与某种对象相关联,但原因在于应用程序设计,而不是对象引用层次结构或垃圾收集器行为。

          实际上,要说内存泄漏总是与“常规”长寿命对象相关联 - 我会说错误。但仍然具有误导性,如上所述。

          【讨论】:

            【解决方案7】:

            由于 Java 真正分配内存的唯一时间是在创建对象时(嗯,对象和数组,但相同的差异),这绝对正确,但不是很有用。

            说为什么这些对象是长寿的会更有用。

            如果您正在撰写论文或其他内容,我会描述导致对象被保留的对象树的“根”。

            这些包括:

            • 堆栈上的临时变量(任何线程的)
            • 静态变量(来自任何类)
            • 来自 JNI 本机代码的特殊参考

            我相信还有更多,我从感觉旧的文档中复制了这个。我知道 RMI 可以保存未回收的引用(我猜可能属于“JNI”项目符号)

            【讨论】:

              猜你喜欢
              • 2012-12-22
              • 2011-10-11
              • 2016-04-17
              • 2012-10-31
              • 1970-01-01
              • 1970-01-01
              • 2014-06-20
              • 1970-01-01
              • 2010-12-04
              相关资源
              最近更新 更多