Java 堆大小因 Infinispan 缓存而变得太大

标签 java caching garbage-collection jboss6.x infinispan

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

当我启动 jboss 时,java 堆大小为 1.5Gb 到 2Gb。 -Xmx 设置为 jboss 分配的最大内存为 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-500mb,什么可以保留这么大的内存? 是我的垃圾收集设置有问题吗?或者我应该查看 Infinispan 设置?

谢谢!

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

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

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

最佳答案

您可能看到的是 JVM 没有收集已从缓存中逐出的对象。一般来说,缓存与分代 GC 的流行思想有着奇怪的关系。

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

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

如果发生这种情况,那么您有几个选择:

  • 忽略它,让完整的 GC 语义完成它的工作,只需知道这就是正在发生的事情即可。
  • 尝试调整 GC,以便对象需要更长的时间才能晋升到终身代。有一些GC flags这可以帮助解决这个问题。

关于Java 堆大小因 Infinispan 缓存而变得太大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36966494/

相关文章:

java - 使用后是否需要将局部变量设置为NULL

java - 如何使用 Cayenne 4.0 + PostgreSQL 9.4 管理 PK 生成

java - 生成除特定值以外的随机数

javascript - React SPA 强制加载新的 JS 构建(包括移动)

c++ - LRU 缓存 C++ 实现

sql-server - SQL Server 2000 中的缓存功能结果

java - 如何读取 "jstat -gcutil <PID>?"的输出

java - 如何使用 Java 在 Azure 服务总线中创建队列?

java - 基于 Hadoop MapReduce 的 Web Java 爬虫

garbage-collection - 当观察模式导致 GC 问题时