Eric created CXF-9146:
-------------------------

             Summary: ThreadLocalClientState should use ThreadLocal
                 Key: CXF-9146
                 URL: https://issues.apache.org/jira/browse/CXF-9146
             Project: CXF
          Issue Type: Bug
            Reporter: Eric


{color:#000000}Is defined as following:
{color}
{code:java}
public class ThreadLocalClientState implements ClientState {

       private Map<Thread, LocalClientState> state = 
Collections.synchronizedMap(new WeakHashMap<Thread, LocalClientState>()); {code}
... which does not make any sense to me, as is this is just ThreadLocal built 
at home, a class which as been in the JDK for a very long time.. A WeakHashMap 
of Threads might emulate ThreadLocal,  but it can cause unexpected memory 
leaks, because the Weak-Keys are strongly helt until the Map is accessed for 
the next time.

 

Let's take this simple example:
{code:java}
var mb = 1024 * 1024;
var rt = Runtime.getRuntime();
var entries = new WeakHashMap<Object, byte[][]>();
var keys = new ArrayList<>();

System.gc();
System.out.printf("Memory before Memory Load: %s mb%n", (rt.totalMemory() - 
rt.freeMemory()) / mb);

IntStream.range(0, 100).mapToObj(i -> new Date(i + 1000)).forEach(key -> {
    keys.add(key);
    entries.put(key, new byte[1][10 * mb]);
});
System.gc();
System.out.printf("Memory after Memory Load: %s mb%n", (rt.totalMemory() - 
rt.freeMemory()) / mb);

keys.clear();
System.gc();
System.out.printf("Memory after Memory Keys clear: %s mb%n", (rt.totalMemory() 
- rt.freeMemory()) / mb);

System.out.printf("Map Size:" + entries.size());
System.gc();
System.out.printf("Memory after first Memory Map access: %s mb%n", 
(rt.totalMemory() - rt.freeMemory()) / mb);{code}
This leads to the following output:

 

Memory before Memory Load: 13 mb
Memory after Memory Load: 1213 mb
Memory after Memory Keys clear: 1213 mb
Map Size:0Memory after first Memory Map access: 13 mb

 


Please ignore my inaccurate measurements with System.gc() without using JMH, 
but when looking up the source for WeakHashMap then it becomes obvious that no 
cleanup is technically possible until the WeakHashMap is deferenced for a 
Map-Operation.

 

This is a scenario which should rarely happen in a production enviroment, but 
we have seen it at least once being the cause of an OutOfMemoryException wenn 
many threads i in parallel executed requests which returned very large 
Responses in Memory.

 

Therefore, and especially when thinking of the future of virtual threads and 
scoped values, I would advise to the refactor the code so that it internally 
uses a simple Treadlocal from now on instead of the WeakHashMap.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to