background
-
It is recommended to read the basics of ThreadLocal and its basic use. ThreadLocal Understanding 1: Basics and Applications
-
MemoryLeak
After a program applies for memory, the system cannot release the memory space that has been applied for. A small amount of memory leakage can be ignored. However, memory leakage slowly accumulates, resulting in serious consequences.
-
OutOfMemory
The system does not have enough space to allocate when applying for memory. That is, more memory is allocated than the system can give, so an overflow occurs.
-
A memory leak will eventually lead to a memory overflow.
Causes a memory leak example
- code
- use
Solution Examples
- code
2. use
Process analysis
-
The num attribute variable is ThreadLocal< Integer > and is static. The num static variable in the JVM is loaded (load -> connect -> initialize -> use -> unload). Use and unload without analysis.
-
The connection phase consists of three parts: validation -> preparation -> parsing.
-
In the preparation phase, the value of num is set to null.
-
Initialization. Num is a specific instance of ThreadLocal< Integer >. The address of the static variable instance is in the metadata space, as jdK1.8 and beyond call it. It’s direct memory. The actual contents of the object instance NUM are stored on the heap.
-
Analyze relationships between classes
Thread has an attribute called ThreadLocalMap. When a ThreadLocal instance executes set(), the ThreadLocalMap property (threadLocals) of the current thread is set to an instance that is thread-private and therefore thread-safe. This ThreadLocalMap has a weakly referenced static inner class Entry that holds keys and values. Entry< ThreadLocal t, t v >. T is generic. And this weak reference is only for key(ThreadLocal), T v is a strong reference type.
-
Num and V analysis
The Entry key of each thread’s ThreadLocalMap is the same instance (num). It doesn’t really matter whether num is null or not, or whether it will be dropped by GC, because no matter how many threads are started, num is always one. However, if the program actively sets NULL, GC will be accelerated.
The thing to think about is T, where T is generic knowledge in Java, which is essentially our value V. The reference relationship here is that each thread has its own Java virtual machine stack and we’re referring to ThreadLocalMap, and ThreadLocalMap holds the Entry of the instance weak reference, and the key in that Entry, we don’t have to think about it, we don’t have to think about it. The key is the value v of the generic T. We need to null v when threads are not using values in ThreadLocalMap to speed up GC. V is stored in heap memory, and once null is set, it must be cleared by the next GC.
-
After analyzing the whole process, how do memory leaks occur?
If we have a worker thread that does the computation of the values in ThreadLocalMap, but this worker thread does a lot of other computation. It is possible that the thread will spend some time executing other business logic. The JVM tells us that if an object is strongly referenced, it will not be removed by GC the next time it comes. If Eden is being used by another business thread in the Java process, Constantly creating objects and applying for heap memory. During this small period of time, this v may be GC multiple times, but none of them are GC removed. It moves repeatedly between the Cenozoic zones, from and to, and may eventually be elevated to the old age. If, at this point, the system is being used by many users, then almost every thread is, causing a memory leak because V is on the heap, but the business logic is no longer using V.
-
The consequences
Gc becomes more frequent, and then the old generation fills up a lot of V objects. If there are a lot of threads, then there is a heavy GC, which we call Full GC, which is actually STW(Stop the world). At this point, the system will no longer receive new requests, and all other business threads in the system will stop executing.
Not handling a memory leak can end up causing a heavy GC for the JVM. This process is actually a memory leak, because not collecting in time can slowly cause a memory leak. Therefore, it is ok to understand both memory leak and memory overflow. It’s just not that precise.
-
The solution is to call ThreadLocal’s remove() method. You need to pay attention to the timing of the call.
-
The follow-up plan
The ThreadLocal process and implementation details are documented.
summary
-
Understand what memory leaks and memory spills are.
-
What usage may cause memory leaks and how to fix them.
-
How a memory leak can lead to an overflow.
-
Analyze problems and explore the reasons behind them.
-
A picture is worth a thousand words. I will draw diagrams to help me understand the relationships of ThreadLocal classes, as well as the working process and implementation details.
-
Solution: Call the remove() method as soon as the thread is done using the T v in ThreadLocalMap.