How to Find Memory Leaks in Java Web Applications
Finding memory leaks in your Java application could be a needle in a haystack exercise if you are a rookie or intermediate Java developer who is yet to know their way around the Java Virtual Machine (JVM) production environment. However, depending on your profiling tool, you can easily analyze your Java memory consumption, while obtaining instantaneous insights into the heap in your Java production applications. But before we go into the details on how to find memory leaks in java web applications, let’s get into what a Java memory leak is, the possible causes of such leakages, and remediation procedures to handle this.
Java Memory Leak
A memory leak is simply caused by reference chaining which is held up in the PermGen and cannot be garbage-collected. Sounds gibberish, right? Well, keep calm and follow through while I explain further. Since web containers utilizes a class to class loader mapping system to isolate web applications and because a class is uniquely identified by its name and the class loader that loaded it. Hence, you can have a class with the same name, loaded multiple times in a single JVM – with each class having a distinct class loader.
- An object retains a reference to the class (java.lang.Class) that instantiated it.
- The class in turn retains a reference to the class loader that loaded it.
- The class loader retains a reference to every class it loaded.
This potentially becomes a very big reference graph to handle on a long run. Not to forget that these classes are loaded directly into the PermGen. Therefore, retaining a reference to a particular object from a web application pins every class loaded by the web application in the PermGen. These references often remain even after a web application is reloaded and with each new reload, more classes get pinned or stuck up in the PermGen – which in due course gets full.
What Is A PermGen?
PermGen, short for Permanent Generation is a heap in the JVM dedicated to storing the JVM’s internal representation of Java Classes – and also detained string instances. In simple terms; it is an exclusive heap location separate from the primary Java heap, where the JVM registers metadata related to the classes which have been loaded.
Although, most Java Servlet containers and WebSocket technologies enable the org.apache.catalina.core.JreMemoryLeakPreventionListener Class by extension such as Apache Tomcat 7.0 and upwards. Nonetheless, the inclusion of this memory leak handler wouldn’t suffice in the event of a more sophisticated such as PermGen errors on reload and bug interference caused by the application itself. This gets a little more interesting when the Tomcat servlet isn’t causing the leak, neither is the application (at least not directly) but rather a bug in the JRE code triggered by some third-party library.
With the advent of the Java Development Kit – JDK6 (Update 7 or later), comes a handy tool that ships with the JDK and makes life a whole lot easier for us. This tool is called the VisualVM; which is a graphical tool that seamlessly connects to any JVM and allows you to expel unwanted garbage from the JVM’s heap besides letting you navigate that heap. In a Tomcat servlet, a class loader for a web application is also a class called org.apache.catalina.loader.WebappClassLoader. Wherefore, if our Tomcat instance has just a single web application deployed, then there should only be one instance of this class in the heap. But in the event that there are more, then we have a leak.
Steps to find memory leaks in Java web applications
Now that we have that out of the way, let’s quickly dive into the steps on how to detect and avoid Java memory leaks. Let’s immediately lucubrate on how we can use VisualVM to figure this out.
3. Click on the ‘OQL Console’ button at the top of the Heap Dump navbar.
This opens up a console that allows you to query the heap dump. For this exercise, we want to locate all instance of org.apache.catalina.loader.WebappClassLoader. Enter the command below in the resulting console;
select x from org.apache.catalina.loader.WebappClassLoader x
4. In this case, VisualVM found two instances of the web application class loader; one slated for the web application itself and the other for the Tomcat manager application.
Use the Tomcat manager application to restart the web application at http://localhost:8080/manager/html and take yet another heap dump of the Tomcat process.
5. Notice the inclusion of an extra instance from the above step.
This is because one of these 3 instances was supposed to be collected by the garbage-collector, yet it wasn’t. Thanks to Tomcat we can easily tell which instance was not garbage-collected as all active class loaders are provisioned with the field name: ‘started’ set to ‘true’.
In order to find the invalid instance, click through each class loader instance until you find the one whose ‘started’ field is set to ‘false’.
6.Determine what object is holding a reference to the class loader
Now that we have spotted the class loader that causes the leak, we need to determine what object is holding a reference to the class loader. Evidently, a good number of objects would be referenced by many other objects, but in all essence, only a limited number of these objects would form the root of the graph of references. These are particularly the object(s) we are interested in.
Therefore, on the bottom pane of the instances tab, right-click on the object instances that form the root of the reference graph and select ‘Show nearest GC root’.
The resulting window should look like this;
Figure 6: Right-click on the object instances that forms the root of the reference graph and select ‘Show nearest GC root’.
8. See what is causing the memory leak
From this, we can deduce that this is an instance of the sun.awt.AppContext type. We could also see that the contextClassLoader field in AppContext is holding a reference to the WebappClassLoader. Hence, this is the errant reference causing the memory leak. Now we figure out what instantiated the sun.awt.AppContext type, for starters.
Firstly, we restart the Tomcat in debug mode with the following code;
Then, we move on to remotely debug the class loading sequence – in which case I would be using Eclipse to do this. Also, we need to set a class loader breakpoint on sun.awt.AppContext;
- Use the Open Type Command (Shift+Control+T) to navigate to the sun.awt.AppContext type.
- Right-click on the class name in the Outline pane and choose ‘Toggle Class Load Breakpoint’.
Thereafter, we need to trigger the class loading sequence by connecting the debugger to the Tomcat instance and having the debugger come to a halt exactly at the point where the sun.awt.AppContext is loaded;
And there you go! It has been instantiated by the JavaBeans framework, which in this instance is being used by the Oracle Universal Connection Pool (UCP). We could therefore notice that the contextClassLoader is a final field and it looks like AppContext appears to be a singleton; so we can assume that this field is set once and once only during the instantiation of AppContext.
so we can infer that this field is set once and once only during the instantiation of.
I conveniently added the above code to my servlet context listener, causing it to execute during application start-up and it had the desired effect of remedying this particular memory leak.
How to find memory leaks in Java web applications instantly
Memory Leaks in Java Applications and How to Find Them with FusionReactor
Memory leaks are a common problem in Java applications and can lead to poor performance and crashes. To keep your Java application running smoothly, detecting and resolving memory leaks is essential as soon as possible. This section will discuss memory leaks in Java and show you how to find them using FusionReactor.
How to Find Memory Leaks in Java Applications using FusionReactor
To find memory leaks in Java applications, you need to monitor the heap usage of the application and look for any unusual behavior, such as a consistent increase in the heap size or a high number of objects being created and not being destroyed.
FusionReactor provides a powerful tool for monitoring and managing Java applications, including the ability to detect and diagnose memory leaks. To find memory leaks in a Java application using FusionReactor, follow these steps:
- Monitor the heap usage: Start by monitoring the heap usage of your Java application using FusionReactor. This will give you a baseline for how the heap usage changes over time.
- Identify unusual heap behavior: Look for any unusual behavior in the heap usage, such as a consistent increase in the heap size or a high number of objects being created and not being destroyed.
- Generate a memory dump: If you identify unusual behavior in the heap usage, generate a memory dump in FusionReactor to get a detailed view of the heap and identify which objects are taking up the most memory.
- Analyze the memory dump: Use the memory dump to analyze the objects taking up the most and identify any potential memory leaks.
- Debug the code: Use the information from the memory dump to debug the code and identify the source of the memory leak.
- Resolve the memory leak: Once you have identified the source, resolve it by fixing the code or tuning the JVM settings.
- Monitor the resolution: After resolving the memory leak, continue monitoring your Java application’s heap usage to ensure it performs optimally.
Conclusion – How to Find Memory Leaks in Java Web Applications
Memory leaks can cause severe problems for Java applications, leading to poor performance and even crashes. By using FusionReactor to monitor the heap usage of your Java application, you can quickly and easily identify any memory leaks and resolve them to improve the performance of your application. Whether you’re a Java developer, a DevOps engineer, or an IT manager, FusionReactor is essential for managing Java applications and keeping them running smoothly.