Memory Leaks in Java applications
What is a memory leak in java
Usually when objects are no longer used by an application those object should be garbage collected. But if these objects are still referenced, then the garbage collector can not remove these objects from the working memory. Further there are some objects stay in the memory through out the life of the application (Ex: static variables). So such applications consume more and more memory and it leads to OOM issues.
Memory Leaks vs Production systems
In wso2 I have few experiences analyzing memory leaks in some production systems. The possibility of having memory leaks in a production system is bit high as those systems run longer times without giving restarts. In such cases even if there is a tiny memory leak, it accumulates the leak and at last there can be a significant memory leak. Such memory leaks are hard to recreate locally, but we can give a try by keeping the system running with a load for a longer time.
Reasons for memory leaks
The main reason for memory leaks is poor programming.
- Heavy use of static variables
In a static class it is possible to use a class member without initiating the class. So when using static, before a class instance is created an object of its class will be created in JVM. So such static variables will stay in memory for the duration of the program and are not eligible for garbage collection. - Unclosed streams/connections
This will lead to both low-level resource leak and memory leak. Low-level resource leak can be introduced as a leak of an OS level resource. The JVM uses memory to keep track of these underlying resources which leads to memory leak.
The main reason for unclosing streams and connections is because the developer forgets to close the opened stream/connection. After java 7 we have try-with-resources which does not expect to close the streams manually. - Hashset with objects that are missing their hashCode() or equals() implementations. if we don’t override hashCode() and equals() methods and try to add duplicate entries to a Set, it will not be possible to identify the duplicates and will add multiple duplicate entries to the Set. Also, there is no way of removing these duplicates once it is aded.
What is heap dump
A heap dump is a snapshot of the memory of a Java process at a certain point of time. Heap dump contains Java objects and classes in the moment that the snapshot is triggered.
Why we need to analyze heap dump
Heap dump analysis helps to locate where objects are created and find the references to those objects in the source. The ultimate goal of that investigation is to find objects that consume too much memory and where those objects are being held in the running application.
How to analyze heap dump
1. Capture heap dumps in baseline and high traffic. That means we need to take two heap dumps when the system is healthy and in a high traffic.
Command :jmap-dump:format=b,file=<file-path><pid> where pid: is the Java Process Id, whose heap dump should be captured. file-path: is the file path where heap dump will be written in to.
2. Capture a heap dump just before the system crashes
As it is hard to identify the point where the system crashes we can use following command to get the dump in this point. It is recommended to keep this property configured in all the applications at all the times , as we don’t know when the OOM error will happen.
XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-path> file-path: is the file path where heap dump will be written in to.
java -XX:+HeapDumpOnOutOfMemoryError
3. Identify the objects whose size are grown between step 1 and step2.
Few Memory analyzing tools
- MAT
- Java Flight Recorder
- Eclipse Memory Analyzer
- IBM HeapAnalyzer