Cloud Stack Ninja

I have a .war project which contains logic to set and reset a ThreadLocal<String> before and after receiving an HTTP call. From the tests I have run, I am pretty certain that both these actions are being performed correctly i.e. the ThreadLocal is being cleared soon after being set. To test my project, I have a program that creates 10 threads and calls the server from these threads. After a 1 second wait, this process is repeated about 500 times. My goal is to monitor the heap storage being consumed and ensure there are no memory leaks.

Here are the important observations I made:

  1. Calling the server when ThreadLocal is not being used: The heap size keeps on increasing the whole duration of the test and drops to the pre-test level after test-completion. Heap usage without using ThreadLocal
  2. Calling the server when ThreadLocal is being used (set and then reset): After the calls to the server are completed, the heap retains most of the used up space. Hence, memory is leaking. Heap usage with the use of ThreadLocal

From what I know about the use of ThreadLocals, they might cause memory leaks if not reset properly. However, in my case, I am taking proper care to ensure that the ThreadLocal is being cleared (resetting the ThreadLocal in a finally block. With that said, what is it that could be causing this memory leak and how can I address it?

P.S.: Here are some relevant code snippets from the project:

// Class for handling the ThreadLocal instances
public class EsStateStorage {

    private static ThreadLocal<String> outboundRequestThread = new ThreadLocal<>();
    private static ThreadLocal<String> inboundRequestThread = new ThreadLocal<>();

    public static String getOutboundRequestThread() {
        return outboundRequestThread.get();
    }

    public static void setOutboundRequestThread(String value) {
        outboundRequestThread.set(value);
    }

    public static void clearOutboundThreadStorage() {
        outboundRequestThread.remove();
    }

    public static String getInboundRequestThread() {
        return inboundRequestThread.get();
    }

    public static void setInboundRequestThread(String value) {
        inboundRequestThread.set(value);
    }

    public static void clearInboundThreadStorage() {
        inboundRequestThread.remove();
    }

}
// Setting the ThreadLocal Value before making the HTTP call via rest-template
public TestData getData(...) throws{
    ...
    EsStateStorage.setOutboundRequestThread("TEST_VALUE");
    return restTemplate.exchange(...).getBody();
}
// Resetting the thread storage in interceptors that capture all incoming/outgoing HTTP calls
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    try {
        ClientHttpResponse response = execution.execute(request, body);
        logOutboundCall(request, body, response);
        return response;
    } finally {
        EsStateStorage.clearOutboundThreadStorage();
    }
}


Read more here: https://stackoverflow.com/questions/64410241/threadlocal-causing-memory-leak-even-after-cleanup

Content Attribution

This content was originally published by Tabish Mir at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: