DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • Understanding Root Causes of Out of Memory (OOM) Issues in Java Containers
  • Memory Leak Due To Mutable Keys in Java Collections
  • Advanced Java Garbage Collection Concepts: Weak References, Finalization, and Memory Leaks
  • Java Z Garbage Collector (ZGC): Revolutionizing Memory Management

Trending

  • Testing Java Applications With WireMock and Spring Boot
  • The 7 Biggest Cloud Misconfigurations That Hackers Love (and How to Fix Them)
  • API Standards Are Data Standards
  • 12 Principles for Better Software Engineering
  1. DZone
  2. Coding
  3. Java
  4. Memory Leak Due to Uncleared ThreadLocal Variables

Memory Leak Due to Uncleared ThreadLocal Variables

ThreadLocal variables in Java, if not cleared, can accumulate in memory, causing an OutOfMemoryError. Learn how to clear them after use to avoid memory leaks.

By 
Ram Lakshmanan user avatar
Ram Lakshmanan
DZone Core CORE ·
Jun. 13, 25 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
2.2K Views

Join the DZone community and get the full member experience.

Join For Free

In Java, we commonly use static, instance (member), and local variables. Occasionally, we use ThreadLocal variables. When a variable is declared as ThreadLocal, it will only be visible to that particular thread. ThreadLocal variables are extensively used in frameworks such as Log4J and Hibernate. If these ThreadLocal variables aren’t removed after their use, they will accumulate in memory and have the potential to trigger an OutOfMemoryError. 

In this post, let’s learn how to troubleshoot memory leaks that are caused by ThreadLocal variables.

ThreadLocal Memory Leak

Here is a sample program that simulates a ThreadLocal memory leak.

Plain Text
 
01: public class ThreadLocalOOMDemo { 
02: 
03:    private static final ThreadLocal<String> threadString = new ThreadLocal<>(); 
04: 
05:    private static final String text = generateLargeString(); 
06: 
07:    private static int count = 0; 
08: 
09:    public static void main(String[] args) throws Exception { 
10:        while (true) { 
11: 
12:            Thread thread = new Thread(() -> { 
13:                threadString.set("String-" + count + text); 
14:                try { 
15:                    Thread.sleep(Long.MAX_VALUE); // Keep thread alive 
16:                } catch (InterruptedException e) { 
17:                    Thread.currentThread().interrupt(); 
18:                } 
19:            }); 
20: 
21:            thread.start(); 
22:            count++; 
23:            System.out.println("Started thread #" + count); 
24:        } 
25:    } 
26: 
27:    private static String generateLargeString() { 
28:        StringBuilder sb = new StringBuilder(5 * 1024 * 1024); 
29:        while (sb.length() < 5 * 1024 * 1024) { 
30:            sb.append("X"); 
31:        } 
32:        return sb.toString(); 
33:    } 
34:} 
35:


Before continuing to read, please take a moment to review the above program closely. In the above program, in line #3, ‘threadString’ is declared as a ‘ThreadLocal’ variable. In line #10, the program is infinitely (i.e., ‘while (true)’ condition) creating new threads. In line #13, to each created thread, it’s setting a large string (i.e., ‘String-1XXXXXXXXXXXXXXXXXXXXXXX…’) as a ThreadLocal variable. The program never removes the ThreadLocal variable once it’s created. 

So, in a nutshell, the program is creating new threads infinitely and slapping each new thread with a large string as its ThreadLocal variable and never removing it. Thus, when the program is executed, ThreadLocal variables will continuously accumulate into memory and finally result in  ‘java.lang.OutOfMemoryError: Java heap space’.

How to Diagnose ThreadLocal Memory Leak?

You want to follow the steps highlighted in this post to diagnose the OutOfMemoryError: Java Heap Space. In a nutshell, you need to do:

1. Capture Heap Dump

You need to capture a heap dump from the application, right before the JVM throws an OutOfMemoryError. In this post, eight options for capturing a heap dump are discussed. You may choose the option that best suits your needs. 

My favorite option is to pass the ‘-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<FILE_PATH_LOCATION>‘ JVM arguments to your application at the time of startup.

Example:

Shell
 
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/tmp/heapdump.hprof


When you pass the above arguments, JVM will generate a heap dump and write it to ‘/opt/tmp/heapdump.hprof’ file whenever an OutOfMemoryError is thrown.

2. Analyze Heap Dump

Once a heap dump is captured, you need to analyze the dump. In the next section, we will discuss how to do heap dump analysis.

Heap Dump Analysis: ThreadLocal Memory Leak

Heap dumps can be analyzed using various heap dump analysis tools, such as HeapHero, JHat, and JVisualVM. Here, let’s analyze the heap dump captured from this program using the HeapHero tool.

HeapHero flags memory leak using ML algorithm
HeapHero flags memory leak using ML algorithm

                                        

The HeapHero tool utilizes machine learning algorithms internally to detect whether any memory leak patterns are present in the heap dump. Above is the screenshot from the heap dump analysis report, flagging a warning that there are 66 instances of ‘java.lang.Thread’ objects, which together is occupying 97.13% of overall memory. It’s a strong indication that the application is suffering from memory leak and it originates from the ‘java.lang.Thread’ objects. 

Largest Objects section highlights Threads consuming majority of heap space
Largest Objects section highlights Threads consuming majority of heap space


The ‘Largest Objects’ section in the HeapHero analysis report shows all the top memory-consuming objects, as shown in the above figure. Here you can clearly notice that all of these objects are of type ‘java.lang.Thread’ and each of them occupies ~10MB of memory. This clearly shows the culprit objects that are responsible for the memory leak. 

Outgoing Reference section shows the ThreadLocal strings
Outgoing Reference section shows the ThreadLocal strings


Tools also give the capability to drill down into the object to investigate its content. When you drill down into any one of the Threads reported in the ‘Largest Object’ section, you can see all its child objects. 

From the above figure, you can notice the actual ThreadLocal string ‘String-1XXXXXXXXXXXXXXXXXXXXXXX…’ to be reported. Basically, this is the string that was added in line #13 of the above programs to be reported. Thus, the tool helps you to point out the memory-leaking object and its source with ease. 

How to Prevent ThreadLocal Memory Leak

Once ThreadLocal variables are used, always call:

Shell
 
threadString.remove();


This clears the ThreadLocal variable value from the current thread and avoids the potential memory leaks.

Conclusion

Uncleared ThreadLocal variables are a subtle issue; however, when left unnoticed, they can accumulate over a period of time and have the potential to bring down the entire application. By being disciplined about removing the ThreadLocal variable after its use, and by using tools like HeapHero for faster root cause analysis, you can protect your applications from hard-to-detect outages.

Tool garbage collection Memory (storage engine) Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • Understanding Root Causes of Out of Memory (OOM) Issues in Java Containers
  • Memory Leak Due To Mutable Keys in Java Collections
  • Advanced Java Garbage Collection Concepts: Weak References, Finalization, and Memory Leaks
  • Java Z Garbage Collector (ZGC): Revolutionizing Memory Management

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: