【问题标题】:Growth in old gen memory usage always means memory leak in Java?老一代内存使用量的增长总是意味着 Java 中的内存泄漏?
【发布时间】:2014-04-23 19:33:50
【问题描述】:

我们有几台虚拟机在生产中运行数据服务,客户端向数据服务发送 Restful HTTP 请求,负载有点重(每台主机通常每秒 500 个请求),并且每个虚拟机上的负载总是平衡的。我们在所有主机上都有相同的配置(2 个 CPU,-Xms2048m -Xmx4096m -XX:MaxPermSize=192m -XX:NewSize=512m -XX:MaxNewSize=512M -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+HeapDumpOnOutOfMemoryError)

两天前,我们看到其中 5 台虚拟机上的旧代堆使用量开始增长(每天 300 MB),其他虚拟机上的旧代堆使用量保持不变(大约 80 MB),我们正在尝试识别根原因,请问这是内存泄漏问题还是只是正常情况?老一代内存使用量的增长是否总是意味着 Java 中的内存泄漏?

谢谢。

更新:我们昨天刚刚重新启动了这 5 台主机,所有这些主机上的 old gen 堆使用都像其他主机一样恢复正常,但是,在我们今天早上的峰值负载之后,其中一台主机上的 old gen 堆使用开始了再次成长……

【问题讨论】:

  • 我是这些东西的新手,但我认为 GC 应该完全防止内存泄漏。换句话说,我认为内存泄漏和 java 从来就不是同一句话。
  • Java only GCs 未引用的内存。如果您创建一个 for 循环,不断向列表中添加新对象,您将在说蓝莓派之前耗尽内存。
  • @Takendarkk java 出现内存泄漏并非不可能,但 GC 本身肯定存在错误。我相信有过这样的案例,不过不要引用我的话。
  • @NatanCox 我不确定内存泄漏是否真的与简单地用完所有内存一样。
  • @Nata 在 Java 中完全有可能发生内存泄漏——例如,将越来越多的数据放入您用作缓存的 HashMap 中,而没有任何驱逐/过期策略

标签: java memory-leaks


【解决方案1】:

老一代内存使用量的增长是否总是意味着 java 中的内存泄漏?

不一定。

并发标记清除垃圾收集器在收集期间不会压缩旧代。因此,在足够的内存负载下,可能会产生大量碎片,从而无法回收足够的内存以允许将tenured objects 提升到 old gen 空间。

尝试打开这些参数,看看发生了什么:

-XX:+PrintGCDetails -XX:+PrintPromotionFailure -XX:PrintFLSStatistics=1

查找无法释放大量内存的升级失败和频繁的完整 GC 扫描。

如果您使用的是 Java 7 或更高版本,您可以尝试切换到 G1 collector(-XX:+UseG1GC 而不是 -XX:+UseConcMarkSweepGC)。这是一个压缩收集器,可以避免上述一些问题。

如果在那之后您仍然遇到问题,那么我会查看您的代码,看看是否有东西挂在不应该的对象引用上。

编辑:由于这发生在某些主机上而不是其他主机上,我倾向于代码问题,可能与意外的用户输入有关,因为它只是偶尔发生。

【讨论】:

  • 非常感谢您的帮助!我们已经有了 -verbose:gc -XX:+PrintGCDateStamps -XX:+PrintGCDetails 设置,我检查了过去 7 天没有促销失败。是的,我们正在使用 Java 7,我们将尝试 G1。
【解决方案2】:

听起来您所描述的是内存泄漏。因为对我而言,内存泄漏是指您的内存在没有任何充分理由或开发人员不理解原因的情况下随时间增加。这可能意味着您实际上不需要的一些数据可能由于错误而仍保留在内存中。

我会考虑使用一个好的分析器来找到根本原因。这可能是最简单的。我不知道我是否可以在这里命名产品,但 JProfiler 在我参与的多个项目中拯救了我的团队。

【讨论】:

  • 如果内存无限增长它会,但如果它可以下降它可能不会。
猜你喜欢
  • 2014-12-07
  • 2013-02-20
  • 1970-01-01
  • 2016-07-11
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 2022-12-13
  • 1970-01-01
相关资源
最近更新 更多