Java 内存缓存

问题描述

是否有可能在内存中实现缓存以避免堆满?

我的 spring-boot java 应用程序在内存中使用缓存,过期策略设置为 1 小时(caffeine 库用于缓存目的)。在那之后,所有缓存实例都在老年代,需要一个完整的 GC 来收集。现在 XMX 设置为 10GB,我可以看到经过几个小时的测试,我的缓存包含大约 10 万个实例,但在堆中(正好在老一代)中,我可以找到数百万个缓存对象实例。有没有可能在内存中使用缓存来避免这种情况?

解决方法

您描述的问题是调用内存泄漏。

是的,你可以,但这取决于你使用的 GC 版本。 例如在 G1 中不应该出现这个问题。 所以,如果那是可能的,我建议你切换到 G1。

XpauseTarget 这个标志是用来避免系统长时间停顿的,这样你就可以将清理堆分成几部分。

您还可以自定义需要运行 GC 的百分比。 -XX:InitiatingHeapOccupancyPercent=45

,

正如您所观察到的,缓存和分代收集器有相反的目标。更现代的收藏家如 G1 和 Shenandoah 是基于地区的,这可以让他们更好地处理旧款收藏。在 Shenandoah 技术演讲中,您经常会听到他们的开发人员讨论将 LRU 缓存作为压力测试。如果您的 GC 调整良好,这可能不是问题。

您可以将缓存数据结构保留在堆上,但将其条目移开。这可以通过以访问开销为代价将值序列化为 ByteBuffer 来完成。 Apache Mnemonic 提供了另一种方法,它在堆外存储对象字段并透明地编组数据。这避免了序列化成本,但会侵入对象模型。

有像 Oak 这样的完全堆外哈希表和像 OHC 这样的缓存。这些尽可能多地移动到 GC 之外,但与堆上缓存相比有更多的开销。这类似于使用远程缓存,如 memcached 或 redis,因此可能更受欢迎。例如,Memcached 使用slab 分配来非常有效地处理内存流失。

大多数情况下,您会看到一个小的堆上缓存用于快速本地访问最常用的数据,这些数据由大型远程缓存支持,用于其他所有内容。如果您确实需要多 GB 的进程内缓存,则可能需要堆外缓存,或者您可能必须调整 GC 以适应此工作负载。

,

如果未设置过期时间,缓存中的对象始终存在。您可以做的是调整 JVM 以避免这种情况,即,如果您使用的是 CMS,-XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly,并设置了这两个选项,当老年代超过 75% 时,JVM 将被迫执行 full gc。>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...