Ehcache 2.10.4缓存对象数量查询及过期驱逐失效问题排查
先聚焦你的核心问题——缓存未执行过期/驱逐操作来分析,顺便确认对象数量的正确获取方式:
一、先排查缓存过期配置的参数对应错误
看你的枚举定义:
FAILED_MESSAGES_REPLAY_COUNTS("msgreplaycount", 50000, false, 0, 3600)
而你提到缓存项应仅保留300秒,但你的构造方法参数顺序是(name, maxElementsInMemory, eternal, timeToLiveSeconds, timeToIdleSeconds)——这里你传的timeToLiveSeconds是0(永不过期),timeToIdleSeconds是3600(1小时),和你期望的300秒完全不匹配!
在Ehcache 2.x中:
timeToLiveSeconds:对象从创建到过期的总时长(0表示永不过期)timeToIdleSeconds:对象多久未被访问就过期(0表示永不过期)
你当前的配置意味着:缓存项只要被创建,就会一直存在(因为TTL设为0),同时你的maxElementsInMemory=50000,而当前缓存大小才317,远没达到内存上限,所以驱逐逻辑也不会触发,这就导致所有缓存项一直留在内存里。
修正配置
如果你期望缓存项300秒后不管是否被访问都过期,应该把timeToLiveSeconds设为300,timeToIdleSeconds按需调整(比如设为0):
FAILED_MESSAGES_REPLAY_COUNTS("msgreplaycount", 50000, false, 300, 0)
如果是期望300秒未访问就过期,那调整timeToIdleSeconds=300,同时确保timeToLiveSeconds设为一个大于空闲时间的值(比如600),避免TTL限制提前生效。
二、理解Ehcache过期机制的触发逻辑
即使配置正确,Ehcache的过期也不是实时触发的,它有两种清理逻辑:
- 访问时主动检查:当你调用缓存的
get方法时,Ehcache会自动检查目标对象是否过期,若过期则立即移除并返回null - 后台线程定期清理:Ehcache默认会启动一个后台线程,每120秒扫描一次缓存,清理过期条目。你可以通过配置调整这个间隔:
Cache cache = new Cache(name, maxElementsInMemory, false, eternal, timeToLiveSeconds, timeToIdleSeconds); cache.setDiskExpiryThreadIntervalSeconds(60); // 改为每60秒清理一次 cm.addCache(cache);
如果你的缓存项很少被访问,可能需要等待后台线程运行后,才能看到expired计数增长。
三、缓存对象数量的正确获取方式
你当前用statistics.getSize()是完全正确的,这个方法会返回缓存中当前存活的条目数量。另外也可以直接调用cache.getSize(),在Ehcache 2.x中两者效果一致,都是返回实时的缓存条目数。
需要注意的是,统计功能默认是开启的,你的代码没有显式关闭,所以统计数据是准确的。
四、验证修正后的效果
修改配置后,你可以通过以下方式验证:
- 手动写入几个缓存项,等待300秒后尝试读取,看是否返回null(说明过期被移除)
- 间隔一段时间后查看
expired计数是否增长 - 等待后台清理线程运行后,观察
current size是否下降
内容的提问来源于stack exchange,提问作者markthegrea

