ehcache / ehcache3

Ehcache 3.x line
http://www.ehcache.org
Apache License 2.0
2k stars 578 forks source link

Memory leak when using Eh107CacheManager.getCacheNames() #3229

Open whowrotethiscode opened 2 months ago

whowrotethiscode commented 2 months ago

Hello,

There seems to be a memory leak when using Eh107CacheManager.getCacheNames() in EhCache version 3.9.6:

<config
        xmlns='http://www.ehcache.org/v3'
        xmlns:jsr107='http://www.ehcache.org/v3/jsr107'>

    <service>
        <jsr107:defaults/>
    </service>

    <cache alias="cache-aaa">
        <heap>100000</heap>
    </cache>

    <cache alias="cache-bbb">
        <heap>999999</heap>
    </cache>

</config>
URL config = Test.class.getResource("/ehcache.xml");
CacheManager manager = Caching.getCachingProvider().getCacheManager(config.toURI(), null, null);

while (true) {
    manager.getCacheNames(); // This will eventually run out of memory
}

Each time Eh107CacheManager.getCacheNames() is invoked the collections of "derivedStatistics" is increasing which seems like a bug?

Please see the attached sample code which demonstrates this.

It looks like a possible solution to this problem maybe to change "caches.putIfAbsent()" to "caches.computeIfAbsent()" in refreshAllCaches() to avoid unnecessarily invoking wrapEhcacheCache().

Thanks.

ehcachetest.zip

pbaddi commented 1 month ago

Hi,

I am upgrading net.sf.ehcache ehcache from 2.10.6 to org.ehcache ehcache with 3.10.8 jakarta as classifier. URL configUrl = getClass().getResource("/ehcache.xml"); CachingProvider cachingProvider = Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider"); javax.cache.CacheManager cacheManager = cachingProvider.getCacheManager(configUrl.toURI(), getClass().getClassLoader()); for (String cacheName : cacheManager.getCacheNames()) { } In many places , I am retrieveing cacheName with help of above code.

Is there any alternative get all the cache names if it creating memory leak issue?

In old code, we using below these attributes to display healthcheck of cache. Map<String, Object> cacheMap = new TreeMap<String, Object>(); CacheConfiguration cacheConfig = cache.getCacheConfiguration(); CacheStatistics statistics = new CacheStatistics(cache); cacheMap.put("DiskExpiryThreadIntervalSeconds", cacheConfig.getDiskExpiryThreadIntervalSeconds()); cacheMap.put("DiskPersistent", cacheConfig.isDiskPersistent()); cacheMap.put("Eternal", cacheConfig.isEternal()); cacheMap.put("MaxElementsInMemory", cacheConfig.getMaxElementsInMemory()); cacheMap.put("MaxElementsOnDisk", cacheConfig.getMaxElementsOnDisk()); cacheMap.put("MemoryStoreEvictionPolicy", cacheConfig.getMemoryStoreEvictionPolicy()); cacheMap.put("OverflowToDisk", cacheConfig.isOverflowToDisk()); cacheMap.put("TimeToIdleSeconds", cacheConfig.getTimeToIdleSeconds()); cacheMap.put("TimeToLiveSeconds", cacheConfig.getTimeToLiveSeconds()); cacheMap.put("CacheHits", statistics.getCacheHits()); cacheMap.put("CacheMisses", statistics.getCacheMisses()); cacheMap.put("InMemoryHits", statistics.getInMemoryHits()); cacheMap.put("ObjectCount", statistics.getMemoryStoreObjectCount()); cacheMap.put("OnDiskHits", statistics.getOnDiskHits());

What are alternative in 3.10.8. I could get few attributes but not all.

Is there any doc/example which can help me?

Any help on this appreciated.

Thanks,

whowrotethiscode commented 1 month ago

Hi @pbaddi,

Is there any alternative get all the cache names if it creating memory leak issue?

We are using the following code to avoid the memory leak:

    public List<String> getCacheNames(javax.cache.CacheManager cacheManager) {
        return cacheManager
                .unwrap(org.ehcache.CacheManager.class)
                .getRuntimeConfiguration()
                .getCacheConfigurations()
                .keySet()
                .stream()
                .toList();
    }