Java 堆大小因 Infinispan 缓存而增长过大

use*_*268 0 java caching garbage-collection infinispan jboss6.x

我正在使用 Infinispan 缓存来存储值。代码每 10 分钟写入一次缓存,缓存达到大约 400mb 的大小。它有大约 2 小时的生存时间,最大条目为 1600 万,尽管目前在我的测试中条目数量不超过 200 万左右(我可以通过检查 jconsole 中的 mbeans/metrics 看到这一点) .

当我启动 jboss 时,java 堆大小是 1.5Gb 到 2Gb。分配给 jboss 的最大内存的 -Xmx 设置为 4Gb。

当我禁用 Infinispan 缓存时,堆内存使用量保持在 1.5Gb 到 2Gb 左右。它非常稳定并保持在那个水平。

=> 问题是:当我启用Infinispan 缓存时,java 堆大小增长到大约 3.5Gb/4Gb,这超出了预期。我做了一个堆转储来检查 Eclipse MAT 中缓存的大小,它只有 300 或 400mb(没关系)。所以我希望内存使用量达到 2.5Gb 并保持稳定在这个水平,因为初始堆大小是 2Gb,最大缓存大小应该只有 500mb 左右。

然而,它会随着时间的推移继续增长和增长。每 2 或 3 小时完成一次垃圾收集,这将使用量降低到大约 1 或 1.5Gb,但随后在 30 分钟内再次增加到 3.5Gb。条目数稳定在大约 200 万个,因此这不仅仅是因为更多条目进入缓存。(此外,驱逐次数保持为 0)。

如果缓存只有 400-500 mb,那么什么可以保留这么大的内存?我的垃圾收集设置有问题吗?还是我应该查看 Infinispan 设置?

谢谢!

编辑:您可以在此处查看随时间变化的堆大小。奇怪的是,即使在看起来像完整的 GC 之后,内存也会再次回升到 3Gb。这对应于进入缓存的更多条目。 随时间推移的 Java 堆

编辑:事实证明这与 Infinispan 无关。我将问题缩小到使用大量内存的一行代码(比没有调用时多约 1Gb)。但我确实认为 Infinispan 缓存占用了越来越多的内存,这自然是因为在 2 小时内添加了更多条目。

我还需要有超过 50 个用户在 Infinispan 上查询。当堆达到这样的高值时(即使没有上面提到的内存泄漏),我知道这不是 Java 中的错误场景,但是我需要尽可能多的可用内存。有没有办法“鼓励”堆转储超过某个点?我曾尝试使用 GC 选项为旧代收集给定比例的堆,但通常堆使用量会逐渐增加。

sis*_*hus 5

可能您看到的是 JVM 没有收集已从缓存中逐出的对象。缓存通常与流行的分代 GC 想法有着奇怪的关系。

分代 GC 的想法是,从广义上讲,JVM 中有两种类型的对象 - 生命周期较短的对象,它们被快速使用和丢弃;生命周期更长的对象,通常在应用程序的整个生命周期中使用。在这个模型中,您希望调整您的 GC,以便您将大部分精力放在尝试识别短期对象上。这意味着您要尽可能避免查看长期存在的对象。

缓存通过具有一些中等长度的对象寿命(即几秒/分钟/小时,取决于您的缓存)来破坏这种模式。这些对象通常会被提升到年老代,在需要完全 GC 之前通常不会查看它们,即使它们已从缓存中被逐出。

如果这是正在发生的事情,那么您有几个选择:

  • 忽略它,让完整的 GC 语义做它的事情,并注意这就是正在发生的事情。
  • 尝试调整 GC,以便对象需要更长的时间才能提升到年老代。有一些GC 标志可以帮助解决这个问题。