2

我正在尝试诊断我的 Web 应用程序中的生产内存泄漏。该应用程序是在 Tomcat 7 和 mySQL 上运行的 GWT 应用程序,以及在 Debian 上运行的 OpenJDK 1.6.0_18。

我启动了 tomcat 并让应用程序泄漏了几天——没有重新加载应用程序——然后进行了堆转储并在 Eclipse MAT 插件中打开它。我试图理解我所看到的。似乎从 tomcat 登录类中保存了大量内存(请参见下面的屏幕截图)。

我使用 java 日志框架在我的 GWT servlet 中进行基本日志记录。只是基本的电话,比如

Logger.getAnonymousLogger().log(Level.INFO, "User" + userId + " did something interesting");
Logger.getAnonymousLogger().log(Level.SEVERE, exception.getMessage(), exception);

我在网上能找到的唯一类似的问题是这篇文。

谁能解释这里可能发生了什么?为什么 tomcat 日志记录类会占用这么多内存?

MAT分析截图

更让我困惑的是,它似乎持有大量的弱引用——但我似乎无法在 MAT 中弄清楚如何找出那些弱引用所指向的内容,而且我也期待弱引用当达到堆限制时被收集,但tomcat会抛出内存异常。

大量弱引用

4

1 回答 1

3

有趣的问题:)

看起来有 10 的数百万个班级已经在您的 RootLogger 中注册了记录器。现在,除非您的项目中有数百万个课程,否则:

  • 一个类定期调用Logger.getAnonymousLogger(),或者
  • 记录器或类正在动态生成:
    • 这些可能来自:
      • java.lang.reflect.Proxy
      • 一种脚本语言(如 Groovy),您可以在其中动态创建类
      • 字节码操作库
      • 直接调用new Logger(name)
    • 每个创建的类都会注册一个记录器 - LogManager.addLogger()
    • 一段时间后,Logger(以及任何创建的类)被 GCed

无论哪种方式,每个额外的记录器都会向包含弱引用的 ArrayList 添加另一行。弱引用指向记录器开始,但记录器正在被 GC 处理,只留下空的弱引用。导致OOM的是大量的弱引用,而不是它们(过去)指向的对象。

修复?

  • 如果您使用匿名日志记录,请不要。这是供小程序使用的。
  • 看看你是否有LogManager.addLogger一个动态类。如果是这样,则强制记录器名称为常量
  • 检查你是否有类似的东西new Logger(variable)。如果这样做,则需要将变量更改为常量。
于 2013-04-09T04:28:32.710 回答