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

老一代内存使用量的增长总是意味着Java内存泄漏?,java,memory-leaks,Java,Memory Leaks,我们有几个虚拟机在生产环境中运行数据服务,客户机向数据服务发送Restful HTTP请求,负载很重(通常每个主机每秒500个请求),每个虚拟机上的负载总是平衡的。我们在所有主机上都有相同的配置(2个CPU,-Xms2048m-Xmx4096m-XX:MaxPermSize=192m-XX:NewSize=512m-XX:MaxNewSize=512m-XX:+useConMarkSweepGC-XX:+CMSClassUnloadingEnabled-XX:+heapdumponAutofme

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

两天前,我们看到其中5个VM上的旧gen堆使用量开始增长(每天300 MB),其他VM上的旧gen堆使用量保持不变(大约80 MB),我们正在试图找出根本原因,请问这是内存泄漏问题还是正常情况?旧一代内存使用量的增长是否总是意味着Java内存泄漏

谢谢


更新:我们昨天刚刚重新启动了这5台主机,所有主机上的旧gen堆使用率都恢复正常,但在今天早上的峰值负载之后,其中一台主机上的旧gen堆使用率又开始增长…

听起来像是内存泄漏。因为对我来说,内存泄漏是指在没有任何好的理由或开发人员不了解原因的情况下,内存在时间上增加。这可能意味着一些您实际上不需要的数据仍然保留在内存中,这可能是由于一个bug

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

旧代内存使用量的增长是否总是意味着java内存泄漏

不一定

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

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

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

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

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

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


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

我对这些事情是个新手,但我认为GC应该完全防止内存泄漏。换句话说,我认为内存泄漏和java从来就不是同一句话,java只是没有被引用的GCs内存。如果您创建一个for循环,不断向列表中添加新对象,那么在您可以说blueberry pie之前,您将耗尽内存。@takendark java不可能出现内存泄漏,但GC本身肯定有一个bug。我相信也有类似的情况,不过请不要引用我的话。@NatanCox我不确定内存泄漏是否真的等同于耗尽所有内存。@Nata在Java中完全有可能发生内存泄漏——例如,将越来越多的数据放入用作缓存的
HashMap
,没有任何驱逐/终止政策,非常感谢您的帮助!我们已经有了-verbose:gc-XX:+PrintGCDateStamps-XX:+PrintGCDetails设置,我检查了过去7天没有升级失败。是的,我们正在使用Java7,我们将尝试G1。如果内存无限增长,它将是,但是如果它可以下降,它可能不是。