【问题标题】:Possible Memory Leak?可能的内存泄漏?
【发布时间】:2011-01-03 00:42:22
【问题描述】:

我有一个正在运行的 java webapp,我正在使用 visualVM 进行监控。

这是堆的图表:

使用两组请求进行了测试,一组在 3:20,另一组在 4:40 aprox(它们在图中表示为仅有的两个峰值)。

我的问题是:这是否意味着我有内存泄漏?我担心中间部分,虽然 GC 运行,但堆始终保持在 250MB。

非常感谢您的见解。

【问题讨论】:

  • 样本大小为 2 并不能真正提供足够的信息来声明泄漏。是的,可以在该图中隐藏一个:最右边的分配大小大于最左边的大小。或者,正如 binil 所提到的,只是一些对象被提升到了终身代,而你没有一个主要的 GC。
  • 真的,确定是否存在泄漏的唯一方法是比较随时间保留的活动对象的数量。我已经发布了一篇文章(这里)(kdgregory.com/index.php?page=java.outOfMemory),讨论了如何分析堆转储。

标签: java memory-management memory-leaks profiling


【解决方案1】:

3:20 的第一个请求导致保留了一些内存,但请注意第二个请求之后的 GC 回收了大部分内存。另外我认为major GC是在4:40的第二次请求之后才执行的。

看起来没有泄漏。我的理论是 3:20 的请求导致年轻代被填满,由此产生的 Minor GC 将一些对象提升到了老年代。由 4:40 的请求引起的下一个主要 GC 清理了大部分。

您可以通过在 3:20 发出与请求相同的请求之前使用分析器标记堆来验证这一点,强制进行完整的 GC,然后检查哪些对象在逗留。我不确定 VisualVM 是否允许您 (1) 标记堆并 (2) 强制执行完整的 GC,但 OptimizeIt 曾经这样做。

【讨论】:

  • 非常感谢 binil。你能给我指出一个很好的参考文档来了解所有这些概念吗? (年轻代、老年代、不同类型的 GC 运行等)
  • 确实,对visualGC 插件的进一步检查表明,对象被提升到堆的另一部分。
【解决方案2】:

你是说 3:20 之前没有请求吗?如果是这样,我会说我没有看到任何泄漏的证据。

我不了解您的应用,但它是典型的(基于架构/设计)一些对象在 JVM 的生命周期中徘徊,在第一次使用应用时被初始化。

【讨论】:

    【解决方案3】:

    您使用的是什么 JRE?将哪些堆/GC 相关参数传递给应用程序?

    峰值还不错(如果服务器有更多的待办事项,那么峰值增加是有道理的)。但是看起来不太好,4:40 之后的水平(当负载再次变低时)比负载上升之前的水平更高。不过没必要……

    现在您应该更详细地了解哪些对象或对象图保存在堆中。所以再次运行相同的测试,包括(使用分析器):

    • 在负载上升之前拍摄堆快照
    • 在负载下降后拍摄堆快照(一定要手动触发 GC)

    现在您应该分析差异以及是否看到奇怪的对象,这些对象本应被丢弃。

    【讨论】:

      【解决方案4】:

      JvisualVM 允许您强制进行垃圾回收。

      尝试使用它来看看会发生什么。

      【讨论】:

      • 它实际上是强制它,还是它调用 System.gc()?
      • 我相信它强迫它。也许它只是 Sun JVM。
      • 它实际上调用了System.gc() 它并没有强制执行任何操作。
      【解决方案5】:

      这里的内存泄漏是什么意思?我不认为像 SUN 这样好的 JVM 实现会有如此疯狂的错误。当您没有引用内存位置(僵尸)或者您没有任何可能回收它时,理想地使用内存泄漏词。如果你有错误的编程习惯,你持有对不再使用的对象的引用并且它们在更大的范围(生命周期)中,那么你会消耗更多的内存而不给 GC 重新收集它的选项。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多