【问题标题】:Java Empty the cache before OutOfMemoryErrorJava 在 OutOfMemoryError 之前清空缓存
【发布时间】:2013-01-07 09:48:41
【问题描述】:

有没有可靠的方法在内存满之前清空缓存? 或者根据当前可用的“实际”空闲内存(硬引用对象)更好地限制缓存?

软引用缓存不是一个好主意,因为 GC 惩罚很高,一旦达到限制,所有缓存条目都需要重新加载。

另外,runtime.freeMemory() 的值对我的目的来说也不是那么可靠,因为即使它太低,在下一个 GC 周期之后也可能有足够的可用空间,因此它不能很好地指示实际使用的内存。

我试图弄清楚每个原始时间会消耗多少内存,这样我就可以知道缓存的实际内存使用情况并对其进行限制,但找不到可靠的方法来计算出需要多少内存用于存储大小为 n 的 String 引用。

【问题讨论】:

  • 没有基于字符串的length() 的可靠指标,因为不同的字符串可以共享相同的支持char[] - "This is a very long string".substring(5,2) 是字符串is,但它包含一个引用到“很长”char[]
  • 这里的答案也许能给出一个想法。 stackoverflow.com/questions/13855013/…

标签: java caching memory-management garbage-collection jvm


【解决方案1】:

有两个或三个集合。如果你想降低服务的内存可用性,你可以拥有。

  • 最近条目的地图,例如LinkedHashMap。
  • 软参考地图。
  • 弱引用图。

您可以控制每个映射的大小,因为弱引用可以在次要收集后清除,软引用将在需要时清除,强引用映射具有始终保留的核心数据。

顺便说一句:如果您经常达到内存限制,您应该考虑购买更多内存,每个 JVM 最多可达 32 GB。您可以花不到 200 美元购买 32 GB。

【讨论】:

  • 这会有什么不同?如何确保缓存不会导致 OutOfMemmoryError?我的应用程序在 GAE 云服务器上运行,因此添加更多内存并不便宜。
  • 不同的是;您至少可以缓存少量条目,并且您不会得到 OOME,除非这个小数字仍然太多,即您的应用程序无论如何都将死亡。遗憾的是,云提供商没有跟上新技术的步伐。我 8 岁的孩子在他的 PC 中有 8 GB,因为我花了 24 英镑购买 4 GB 并没有多大意义。
  • 避免 OOME 的最佳方法是减少内存消耗。为此,您需要使用 VisualVM 或理想的商业分析器对应用程序进行内存分析。
【解决方案2】:

尝试最新的 Oracle 1.7 版本之一。他们应该提供 GarbageCollectorMXBean 和 GarbageCollectionNotificationInfo。使用它来监控每个 GC 周期后已使用/未使用的内存量。有一些示例代码here。 然后,您可以按照 Peter 的建议在内存紧张时使用多级缓存来清除外层缓存,但保留较小的一级缓存。

【讨论】:

  • 不幸的是,我希望它与不支持 Java 1.7 的 GAE 兼容,但如果查询托管 bean 的速度足够快,这似乎是未来的发展方向。
【解决方案3】:

我建议最简单的解决方案是将引用更改为弱引用。 这样,当所有强引用都超出范围时,引用仍然可以完成并被垃圾回收。

见:http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html

【讨论】:

  • 正如我在我的问题中提到的,软/弱引用的问题是,一旦内存不足,它们就会被全部清除,从而使所有缓存都变空,这将非常昂贵重建整个地图。我希望它被智能化,只要缓存足够空以释放一些空间,或者只是将地图的大小保持在该阈值以下。
猜你喜欢
  • 2016-01-03
  • 2014-11-06
  • 1970-01-01
  • 2018-11-03
  • 1970-01-01
  • 1970-01-01
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多