【问题标题】:Does and increasing resident memory size in the JVM indicate a memory leak?JVM 中驻留内存大小的增加是否表明内存泄漏?
【发布时间】:2011-12-01 00:38:04
【问题描述】:

我正在使用以下命令行选项启动一个 JBoss 4.2 服务器实例:

-Xms8192m -Xmx8192m -XX:+DisableExplicitGC -XX:MaxPermSize=512m

我没有收到 OutOfMemoryException,但我不希望内存使用量会增加,如果因为它们的引用死亡而被 GC 处理。常驻内存使用量(用 top 测量)从 ~ 4.2G 开始,并在接下来的几天到一周内稳步增加,直到达到 8.4G。我仍然没有收到异常。我担心的是,在重要活动期间(JBoss 消息处理 > 10k mssgs/秒),每 6-10 秒会出现约 100-700 毫秒的处理延迟。这似乎也与常驻内存使用量的增加有关。这发生在具有 2 个四核处理器和 32G 内存的机器上。

我将打开额外的命令行参数:

-verbosegc -XX:+PrintGCDetails

但是,我想知道这似乎是垃圾收集问题还是内存泄漏?几周以来,我一直试图追踪潜在的内存泄漏,并发现了我认为肯定会解决它的 XML 处理问题,但这是一条死胡同。无论是否存在泄漏(尤其是禁用显式 GC),驻留内存使用量是否会攀升以满足 Xmx 的值?如果确实不是泄漏,是否还有其他一些垃圾收集参数可能会有所帮助(例如修改垃圾收集器类型、幸存者比率或暂停目标)?

我知道 100-700 毫秒的延迟看起来并不多,但它有可能在这个应用程序中产生重大影响。提前感谢您提供的任何帮助/建议。

【问题讨论】:

  • 如果您还没有这样做,我建议您使用 JConsole(或其后续版本)监控您的 Java 进程:componative.com/content/controller/developer/insights/jconsole1/…
  • 猜测一下,是不是有什么东西(例如缓存)使用了一堆SoftReferences?
  • @paulsm4 - 我还没有这样做。感谢您的提示,我会检查一下。使用 jconsole 是否会对性能产生影响?
  • @tc - 我不相信有缓存。传入消息替换散列图中的对象,但不添加到散列中。根据 javadocs,如果存在的话,对 HashMap 执行 put 会删除现有对象。那是我能找到的唯一存放东西的地方。
  • @user979273 -- 但是,当然,如果您收到的传入消息与现有消息的密钥不同,它将增加整体大小。还有很多其他地方可以让复杂的服务器存储东西,以及 JVM 本身可能缓存东西的地方。

标签: java memory-management jboss garbage-collection


【解决方案1】:

Java 中“泄漏”的定义与 C/C++ 中“泄漏”的定义大不相同。在 C/C++ 中,当你 mallocnew 一块存储时,你会得到一个“泄漏”,而以后永远不会是 freedelete 它。

但在 Java 中,当然,您永远不会删除任何内容,而是让 GC 来查找不再引用的内容并将其释放。

然而,可能发生的情况是,一些复杂的数据结构被建立起来,然后又建立了一些,然后又建立了一些,有时是无意的。

最明显的情况是类似于 StringBuffer 的东西,它用于累积日志信息并且从不写入/清空。但是你也可以在你的应用程序中拥有一个(故意的)长期存在的结构,你碰巧“停放”了一些(假设是)短期存在的对象,但随后无法null指向“短期”对象的指针你已经完成了它,使它有效地变得不朽。有些事情是显而易见的,有些需要大量调查才能弄清楚。

但在大型服务器中,即使没有此类泄漏,您也倾向于在一段时间内相当稳定地积累“东西”。例如,如果调用给定的应用程序,它可能会导致创建一些对象(或仅加载类,它们间接创建的对象),并且这些对象可能会“徘徊”,直到下一次调用该应用程序。网页缓存之类的东西会填满。如果使用 JSP 之类的东西,将创建对象并“缓存”以供以后使用。

但是这种“东西”的积累应该会观察到一种渐近的行为,随着时间的推移慢慢接近某个稳态值。如果它以稳定状态继续向上,那么您可能确实有“泄漏”。

关于您的 GC 行为,在繁忙的服务器上每隔几秒运行一次 GC 并不罕见。您可以使用调整参数来尝试“平衡”不同的 GC“层”,但这样做有点玄学。服务器上的 GC 性能通常很差,这仅仅是因为 GC 实现不是为服务器精心设计的——繁忙服务器上的 GC 需要能够以大部分并发的方式运行,而大多数 GC 实现都没有做得很好。

【讨论】:

  • 通过过多的日志记录我正在跟踪有可能随着时间的推移而扩展的数据结构,它们似乎不是罪魁祸首。它似乎与应用程序无关,因为有一定数量的实例并且事情在没有任何 ui 访问的情况下增长。这似乎仍然意味着内存泄漏(或未能取消引用不再需要的对象)。问题是,如果是这种情况,当我达到 Xmx 值时,我不应该得到 OutOfMemoryException 吗?没有这个异常是否表明这不是问题?
  • 请记住,您可能已经到达 Xmx。不同的 GC 算法做的方式不同,但是 GC 最简单的“触发”就是等待堆满存储,然后做一次 GC。大多数现在还在分配一定数量的堆(或其他一些此类指标)后启动 GC,以导致更短的 GC 周期更频繁地发生。对于此类系统,瞬时堆大小将显示为锯齿图。问题是,牙齿的尖端是否越来越高,它们的生长速度(如果有的话)是稳定还是缓慢下降?
  • 也许使用-server 运行会有所帮助,但我不知道这是否会改变 GC 算法(这有点像黑魔法)。我认为一些较新版本的 JVM 还允许您指定使用哪个垃圾收集器。
  • @DanielRHicks - 如果确定我是否达到 Xmx 就像使用 top 查看常驻内存一样简单,那么我知道我已经好几天没有达到 Xmx 了。问题在于,随着驻留内存的增加,Jboss 会停止所有处理。它似乎与 JBoss Messaging 上的 thru-put 直接相关,但到目前为止我还没有找到“泄漏”。打开verbosegc至少可以告诉我gc是否是导致暂停的原因,但我不知道这会如何导致驻留内存增加。
  • @tc。 - 感谢您的建议,我实际上已经这样做了,只是忘记将其包含在问题中。
【解决方案2】:

我没有收到 OutOfMemoryException 但我不希望 如果将事物作为其引用进行 GC,则内存使用量会增加 死。

这不一定是正确的。对象可以放置在堆的永久内存中。如果对象被引用超过“短时间”,就会发生这种情况。一旦在任期内,它通常不会被垃圾收集 util max heap 达到。因此,仅仅因为堆内存使用量没有减少并不意味着您有泄漏。

正常的内存配置文件(使用的堆与时间)看起来像锯齿 - 内存使用量缓慢增加直到某个阈值(通常是最大堆),然后由于 GC 而减少,然后又缓慢增加。

【讨论】:

    【解决方案3】:

    我唯一要添加的就是尝试将分析器连接到您的应用程序并查看内存使用情况。我已经成功地分析了 Weblogic A.S. 的实例。使用 jProfiler 和 YourKit,虽然我没有尝试使用 JBoss,但应该相当容易。

    你能在测试环境中复制这种行为吗(因为分析器对性能的影响很大,只有在你绝望时才在生产环境中这样做)?如果这样做,您可以查看 GC 是否仅在达到 XMX 阈值时才被调用(并不意味着有任何问题),并且您可以显式调用 GC 以查看其行为方式。如果即使使用 GC 调用,内存也会持续增加,这可能表明存在问题。

    一个体面的分析器可以告诉您哪些对象的数量增长得更快等等,如果您确实有“泄漏”,这可以极大地帮助您。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-02
      • 2013-07-12
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 1970-01-01
      • 2015-05-17
      • 1970-01-01
      相关资源
      最近更新 更多