EhCache的PooledBasedBackEnd堆内存远超maxBytesLocalHeap阈值如何解决
EhCache 2.9.x堆内存限制不生效问题排查及解决方案
堆限制配置未生效的核心原因
- SizeOf统计中断导致大小计算不准:你配置的
MaxDepthExceededBehavior.ABORT规则下,当缓存对象的遍历深度超过设置的maxDepth=1000000时,EhCache会直接终止对象大小统计,用当前统计到的不完整值作为对象大小,实际内存占用远大于统计值,导致无法触发LFU回收,内存持续上涨。 - EhCache 2.9.0版本已知bug:该版本的
PooledBasedBackEnd、SelectableConcurrentHashMap这两个缓存底层存储结构本身的内存占用,没有计入maxBytesLocalHeap的配额统计,你堆转储里看到的500M+100M的额外占用,就是这部分未统计的内存开销。 - Cache实例未正确关联CacheManager:你代码中直接通过
new Cache(cacheConfiguration)创建缓存实例,没有将其注册到EhCache的CacheManager中,会导致内存配额统计、定时回收等核心逻辑无法正常运行,配置的堆上限不会生效。
有效限制EhCache堆内存占用的方案
修正SizeOf策略配置
将maxDepthExceededBehavior从ABORT改为CONTINUE,同时如果缓存对象嵌套层级特别深,可以适当调高maxDepth值,保证EhCache可以完整计算每个缓存对象的实际大小:sizeOfPolicyConfiguration.maxDepthExceededBehavior(MaxDepthExceededBehavior.CONTINUE);升级EhCache版本或调整配额
2.9.0的内存统计bug在2.10.6及以上的2.x版本已经修复,建议直接升级到EhCache 2.10.9(2.x最新稳定版)。如果不能升级版本,可以手动将存储结构的内存开销纳入预估,将maxBytesLocalHeap配置值下调到原来的1/5~1/3,预留足够的存储结构占用空间。正确关联Cache到CacheManager
不要直接new Cache实例,通过CacheManager创建缓存,保证配置生效:CacheManager cacheManager = CacheManager.getInstance(); cacheManager.addCache(new Cache(cacheConfiguration)); Cache cache = cacheManager.getCache("be_ehcache");额外优化建议
- 如果你不需要堆上的热点缓存层,可以配置
cacheConfiguration.setOnheap(false)直接将缓存值落到磁盘,大幅降低堆内存占用 - 确认缓存的key和value都是可序列化的,避免磁盘换入换出时出现异常
- 上线前通过
cache.calculateInMemorySize()方法验证统计的内存大小是否和实际占用一致,提前排查统计不准的问题
- 如果你不需要堆上的热点缓存层,可以配置
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

