eclipselink icon indicating copy to clipboard operation
eclipselink copied to clipboard

ConcurrentFixedCache can cause memory leak when SessionEventAdapter used

Open alissongdgarcia opened this issue 3 months ago • 1 comments

Here we have a custom SessionEventAdapter which overrides preExecuteQuery and postExecuteQuery to dynamically change the selection criteria of ReadObjectQuery into preExecuteQuery and restore to original after postExecuteQuery. The problem is that ConcurrentFixedCache always add those query objects after this preExecuteQuery (leading to a hashcode change before adding), after adding the hashcode is restored to original one.

This results in a issue due to code on ConcurrentFixedCache inside put method:

            Iterator iterator = this.cache.keySet().iterator();
            try {
                while ((this.cache.size() > this.maxSize) && iterator.hasNext()) {
                    Object next = iterator.next();
                    // Do not remove what was just put in.
                    if (next != key) {
                        this.cache.remove(next); //issue is here, as hashcode changes after adding to map, it never succeeds on this
                    }
                }
            } catch (Exception alreadyGone) {
                // Ignore.
            }

The remove calls never completes properly because as hashcode changes, it doesn't work anymore. This results in a OutOfMemory exception in a long running of the application as it hold a large number of IsolatedClientSessions (nested map reaches thousands/millions of entries instead of just 20).

Probably its better to change the removal to use iterator maybe?

  Iterator<Map.Entry<Object, Object>> iterator = this.cache.entrySet().iterator();
  while (this.cache.size() > this.maxSize && iterator.hasNext()) {
      Map.Entry<Object, Object> entry = iterator.next();
      Object nextKey = entry.getKey();
      if (!nextKey.equals(key)) {
          iterator.remove(); // removes the entire entry safely
      }
  }

This issue is present since EclipseLink 2.x to 4.0.7

alissongdgarcia avatar Sep 26 '25 13:09 alissongdgarcia

Hello, I tried to simulate this bug by attached test application. It's maven project which is based on Apache Derby DB which should be started in the project dir by mvn derby:run. DB DDL initialization script is init.sql . Based on bug description I implemented SessionEventAdapter in com.oracle.jpa.bugtest.domain.ConcurrentFixedCacheSessionEventAdapter, but what is not clear to me which operations are You doing there with org.eclipse.persistence.queries.ReadObjectQuery, that if (next != key) { is not enough and should be replaced by if (!nextKey.equals(key)) {. If it's possible please show it on attached test case.

There are following reasons why I'm asking for additional details:

  • better context which leads into bug understanding
  • for fix like this we usually create unit test too, to describe issue which is fixed and avoid regressions in the future
  • nextKey.equals(key) "cost" more than next != key and there should be performance issue

jpa-bug-2542-ConcurrentFixedCacheCanCauseMemoryLeakSessionEventAdapterUsed.tar.gz

rfelcman avatar Oct 02 '25 11:10 rfelcman