Every Java developer thinks about Java’s automatic garbage collection and worries about memory management. Memory leaks occur when object references are longer needed and poorly maintained. They often put unnecessary pressure on the machine as programs consume more and more resources, and detecting these leaks can be difficult. Existing tools can track and report fine-grained information about individual objects; however, the results are hard to interpret and lack precision.
Four Types of Memory Issues:
- Performance: Mostly associated with excessive object creation, deletion, delays in garbage collection, and so on.
- Resource Constraints: When there is little memory available or more fragmentation of memory allocation for large objects.
- Java Heap Leaks: Java objects are created continuously without being released due to underlying object references.
- Native Memory Leaks: Continuously growing memory utilization outside the Java heap, such as allocations made by the Java native interface code or JVM allocations.
Before finding memory leaks, you should know how and why they occur.
Memory Leaks: A Primer
Memory leakage is a disease and the Java OutOfMemoryError is the primary symptom. OutOfMemoryError can occur due to the generation of several local variables or other events. OutOfMemoryError will happen when desktop applications or client applications run for a long period without restarting the machine. OutOfMemoryError is a common indication of a memory leak. The error is shown when there is insufficient space to allocate a new object. The garbage collector can’t find the necessary space and heap memory can’t be expanded any further.
To diagnose your OutOfMemoryError you need to determine the root cause. OutOfMemoryError appears because the Java heap is full or the native heap is full.
Let’s analyze the possible error messages:
- Java Heap Space: Java heap space doesn’t imply a memory leak; in fact, the problem can be a simple configuration issue. The developer is responsible for analyzing an application that consistently produces OutOfMemoryError.
Assume after some investigation you found that an array instantiation was demanding too much memory. It was not an application fault, rather the application server was relying on the default heap size, which was too small. We can solve this problem by adjusting the JVM’s memory parameters. In other cases, for long-lived applications, this message indicates that memory is holding references to objects and preventing them from being cleaned by the garbage collector.
Another source of OutOfMemoryError arises with the use of finalizers. If a class has a finalized method then objects of that type don’t have their space reclaimed at garbage collection time. Objects are queued for finalization, which occurs later after garbage collection. Finalizers are executed by a daemon thread, and if the finalizer thread can’t keep up with the finalization queue then OutOfMemoryError is given.
- PermGen Space: The PermGen message indicates when the permanent generation is full. The permanent generation is a Heap area that stores class and method objects. When large numbers of classes are loaded then the size of the permanent generation needs to be increased using the “-XX:MaxPermSize” option.
- Interned objects are also stored in the PermGen space. The string class maintains a pool of strings, and when invoked the intern method on it checks the pool for an equivalent string. If available in the pool it is returned back. If not, a string is added to the pool and returns a string with canonical representation. If an application interns a large number of strings, we need to increase the size of our permanent generation.
- Requested Array Size Exceeds VM Limit: The Requested Array Size Exceeds VM Limit error indicates that the application, or any API used by that application, is attempting to allocate an array larger than heap size.
- Example: An application attempts to allocate an array of 512MB but the maximum heap size is 256MB: this will trigger an OutOfMemoryError error message. The problem is either a configuration issue or a bug.
Application Crash without OutOfMemoryError:
An application might crash when memory allocation fails from the native heap. If you are running a native code that doesn’t check for errors, memory will be allocated that is not utilized, causing the application to crash.
- Example: When trying to call the “malloc” function, the system returns NULL if no memory is available. If the malloc function return value is not checked, the application crashes as it attempts to access an invalid memory location. It’s represented as a fatal error log. If the cause of the crash is determined as a lack of error-handling of memory allocations, then you must hunt down the reason for said allocation failure.
Review your code thoroughly to solve memory leaks. To prevent memory leaks, learn about the type of object and its memory allocation. Follow the four easy steps below to solve memory leaks:
- Identify symptoms.
- Enable verbose garbage collection.
- Enable profiling.
- Analyze the trace.
For more information on memory leaks, Java, or other application processes, feel free to engage with us via the comments below or reach out to us here.