ThreadLocal & Memory Leak
PermGen exhaustions in combination with ThreadLocal
are often caused by classloader leaks.
An example:
Imagine an application server which has a pool of worker threads.
They will be kept alive until application server termination.
A deployed web application uses a static ThreadLocal
in one of its classes in order to store some thread-local data, an instance of another class (lets call it SomeClass
) of the web application. This is done within the worker thread (e.g. this action originates from a HTTP request).
Important:
By definition, a reference to a ThreadLocal
value is kept until the "owning" thread dies or if the ThreadLocal itself is no longer reachable.
If the web application fails to clear the reference to the ThreadLocal
on shutdown, bad things will happen:
Because the worker thread will usually never die and the reference to the ThreadLocal
is static, the ThreadLocal
value still references the instance of SomeClass
, a web application's class - even if the web application has been stopped!
As a consequence, the web application's classloader cannot be garbage collected, which means that all classes (and all static data) of the web application remain loaded (this affects the PermGen memory pool as well as the heap).
Every redeployment iteration of the web application will increase permgen (and heap) usage.
=> This is the permgen leak
One popular example of this kind of leak is this bug in log4j (fixed in the meanwhile).
How to clean up Java ThreadLocals in accordance with Sonar?
Sonar is right here.
Each thread will have its own ThreadLocal
state and so its own instance of NumberFormat
.
So in the general case it may be undesirable to not clear data from the state since the thread may be reused (recycled by the server) and the state valued for the previous client may be inconsistent for the current client.
For example some clients could have the format US
, others the format FR
, and so for...
Besides some threads could instantiate that ThreadLocal class, other no. But by not cleaning the state, the state will be still use memory for threads that may not need them.
Well, in your code, there is not variability of the ThreadLocal
state since you set the state for any instance, so no inconsistency risk is likely, just memory "waste".
Now, I adopted the ThreadLocal approach in order to reuse NumberFormat
instances as much as possible, avoiding the creation of one instance
per call
You reuse the ThreadLocal
state by a thread request basis.
So if you have 50 threads, you have 50 states.
In web applications, the server maps the client HTTP request to one thread.
So you don't create multiple instances of the formatter only in the scope of 1 http request. It means that If you use the formatter one or two time by request processing, the ThreadLocal
cache doesn't bring a great value. But if you use it more, using it makes sense.
so I think if I called remove() somewhere in the code, I
would lose all the advantages of this solution
Calling remove()
will not hurt performance if you do that when the request processing is done. You don't lose any advantage since you may use the formatter dozen of times in the scope of the request and it will be cleaned only at the end.
You have Request Listener in the servlet specification :
https://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequestListener.html.
You could do that in void requestDestroyed(ServletRequestEvent sre)
.
Threadlocal memory leak in Threadpool
Clearly, something is creating that / those ThreadLocal instances. If it is not your code, then it must be some library you are using, or (unlikely) Tomcat itself.
I would start by looking at what might be creating instances of
org.apache.http.impl.cookie.DateUtils$DateFormatHolder$1
(That's an anonymous class in a nested class in DataUtils
, by the way ... so unless something weird is coing on, the creation will be occuring in the DateUtils.java
file.)
If examining the source code doesn't help, try debugging the Tomcat instance and setting a breakpoint on the ThreadLocal constructor(s).
Related Topics
How to Enable the Java Keyword Assert in Eclipse Program-Wise
How Do Format a Phone Number as a String in Java
Localdate to Java.Util.Date and Vice Versa Simplest Conversion
Is It Worth to Use Slf4J with Log4J2
Javafx Exception in Thread "Main" Java.Lang.Noclassdeffounderror: Javafx/Application/Application
How to Change the Highlight Color of a Focused Jcombobox
Get Integer Value of the Current Year in Java
How to Use Classloader.Getresources() Correctly
Keystore Type: Which One to Use
How to Handle It with Scanner (Java)
How to Get Windows Username in Java
How to Get a List from Some Class Properties with Java 8 Stream
Parsing Nested JSON Data Using Gson