Spectrum Future Tech
Engineering · Article

Causes of a Memory Leak in Java. Problem Types and Ways to Fix Them

Learn what memory leaks are in Java, their types, symptoms, what causes them, and operative strategies for preventing them.

June 6, 202213 min read
Causes of a Memory Leak in Java. Problem Types and Ways to Fix Them

Leaders investing in engineering rarely struggle with the idea — they struggle with execution. This analysis of causes of a memory leak in java. problem types and ways to fix them focuses on practical trade-offs: what to build first, what to integrate early, and where teams lose momentum after the first release.

In practice, choice of working with Java, which opens up a broad set of possibilities for programming, is well-founded. This is a typeset, high-level programming language created by Sun Microsystems, later redeemed Oracle, with fairly flexible syntax. For more than 20 years, Java has maintained its popularity, taking one of the leading positions in the market of world technologies.

One of its advantages is automated memory management in Java, especially when compared to the C and C++ languages, which don't have this function. It's performed using the built-in garbage collector technology «Garbage Collector» or GC. To explain this critical feature, it's worth noting that the system accumulates in its memory objects that occupy memory but are not used. That tool significantly helps in the elimination of such a problem like a memory leak.

Of course, Java is not the only system that has such an critical and useful function as a garbage collector. But in addition to its other features, such as HotSpot optimizer or excellent backward compatibility, comparison – Java certainly stands out among other platforms.

So what's the problem if Java has such a useful function of distribution and clearing of memory? Let's see.

What are memory leak and their causes

To better understand the essence of a direct example, you should start with the Java memory structure.

Java application data can be stored in spatial blocks such as «Stack» or «Heap.»

  • Stack memory is a repository of store references to «Heap» elements and types of primitive value;
  • Heap contains dynamic objects referenced by variables in the stack.

Consequently, under default settings, a heap can occupy much more space in memory than a stack. However, these settings can be changed manually by setting the heap size below the stack value after increasing it.

Stack has the LIFO principle (enters last, leaves first). Whenever a new method is called with reference to an element or a primitive value, a block of memory is released at the top of the stack:

In practice, heap, unlike the stack, is not cleaned by itself. So, the system is in dire need of a garbage collector function. Without its presence, we can manage only the size of the heap:

A reference to an object from a heap that may contain a stack variable becomes a suitable target over time for the garbage collector, depending on its type. And, when red-colored items appear in the heap memory, they can be assembled by the collector.

Java memory leak is a kind of error when GC leaves elements in the system that are not used. This may occur because of the inability to remove some garbage items that may be referenced in the stack.

In practice, leak has a negative impact on the capacity to use the resources of the system and its overall productivity. If this problem is ignored, the system can completely exhaust data storage space, and end with an irreversible error, «Java Out Of Memory Error.»

It's better to use tools of memory management to fine-tune it. The most relevant of them:

  • OpenView Operations (OVO) by HP;
  • JMETER by Apache;
  • IBM Tivoli by IBM;
  • JProbe Profiler by TechRepublic.

Memory leaks in Java can occur due to unforeseen errors in the code, which keeps references to unwanted objects in the cloud. These links block GC functions. Consequently, it's not possible to clean the repository, which is not usefully used by these elements.

  • Unlimited caching;
  • Overflow of files in one session;
  • Excess of replacement operating system pages;
  • Bugs in the system of users data;
  • Inserting elements in a collection without deleting them;
  • Non-reproducible ways of listening.

Info for detailed analysis of memory leaks in Java, you can find here:

Memory leak in Java and its types Various types of leaks are possible. Their differences are based on how they arise and what caused them.

The majority of common types of leaks:

In practice, life cycle of static fields in Java usually corresponds to the application session time, without taking into account garbage collection with «ClassLoader» capabilities. When analyzing the heap of memory during command execution, we can observe an increase in memory between control points 1 and 2:

But stopping method «populateList()» at the point 3, in VisualVM – heap repository remains untreated. But if you don't take into account «static» in line 2, it will change the memory values:

In this case, after manipulation with the method «populateList()», the heap memory is cleaned by the collector, as all references to objects are deactivated:

Availability of internal classes with reference to external

To initialize static classes, you always need examples from external classes. Each non-static default class contains a hidden reference to the class in which it's saved. If you use an internal class object – it will not collect by GC, even if you close an external class object.

For example, take a class that contains a non-static value and has a reference to several volumetric elements. In this case, the creation of an internal class object has such statistical indicators:

Banal change of the value of the internal or anonymous class to a static, the memory values change radically. This can occur as a result of the contents of the internal class of references to objects external, thus blocking the main function of GC.

Whenever we create a new connection or open a thread, the JVM always allocates space in memory for new threads or connections. Such connections may have session objects with a comprehensive database.

If we leave such resources not closed, we risk allowing the storage to become blocked. This creates the risk that the garbage collector will not be able to detect and remove these objects. And if you ignore the maintenance of stable and correct closing of resources, they will fill up the memory, up to the appearance of an error «Java Out Of Memory Error.»

In the scheme, when we have a class with a redefined finalize() method, its object may not collect GC in time but will queue for deletion. In addition, incorrectly overridden code in finalize() and its speed mismatch to garbage collector can cause an error «OutOfMemoryError.»

For example, take a class with its redefined method finalize() and for which time is needed. If you have a large number of elements collected by GC, such a score of the heap is formed:

If you simply remove a redefined finalize(), you can get this value:

In the Java system version 6, it was necessary to be careful about the use of volumetric strings. Version 7 moved the change of the string pool that moved to HeapSpace from PermGen. If you call a method «intern()» to read a large string – it is saved to a string pool in constant memory (PermGen). This method is stored in PermGen until the end of the session, which causes the application to run out of memory.

An example of permanent memory is when reading a string of a file without its international:

ThreadLocal – a tool that creates stream security by closing the values of its variables. Meanwhile, all threads have a hidden link to the duplicate ThreadLocal variable, and save their copies instead of using the resource in all threads.

In practice, feature, besides its usefulness – has errors. They can affect leaks when misused.

ThreadLocal variables must be collected by GC after deleting the thread that contains them. However, some system servers may not be able to use this feature right. This can occur because the server does not create a new thread for all requests but applies the entire thread pool.

Pools in servers reuse threads, making them inaccessible to the garbage collector and taking up memory.

Implementing incorrect equals() and hashCode()

In creating new classes, we can often encounter the override error of equals() and hashCode() methods. Such methods are commonly used by HashSet and HashMap, and if they contain override errors, this can cause excessive memory consumption.

For example, you can use the ORM Hibernate, which takes the equals() and hashCode() methods to process items and store them in the cache. In the event that these methods are not overridden, Hibernate will not analyze the items, and the cache will fill their copies, causing a memory leak.

Symptoms and Java memory leak detection

There are several suspicious points that may indicate a leak:

  • persistent and unforeseen system failures;
  • unstable application functionality support;
  • an error «Java.lang.OutOfMemoryError» occurred during a long session;
  • connection object removal by the system;
  • meaningful reduction in overall system performance.

to detect a leak, several tools and techniques are required, as well as a combination of them. There is a list of the trusted methods:

Memory profilers – tools that track files and items that take up space in the repository. They are able to detect leaks and analyze the correct distribution of the elements used in the system. Also, estimate the time taken to process away.

In practice, the majority of common tools for profiling Java memory:

  • JProfiler by EJ-Technologies;
  • Java VisualVM by Oracle Corporation;
  • YourKit by Yourkit GmbH.

Engagement heap dump. This is a tool for creating instant and timely snapshots of the heap in the Java memory store. Such images are needed to control the number of objects used and their weight in memory. Also, the tool tracks the number of elements created by the system and what may affect the leak.

Activating the verbose garbage collection log. This tool is able to demonstrate changes to heap configuration in the repository and GC. It provides the most accurate features and performance of the application. And optimizes the collector's performance by identifying suitable elements in the heap, its alternative methods, and JVM parameters.

For example, activate a verbose collection in app using JVM startup methods:

«-XX: +UseSerialGC -Xms1024m -Xmx1024m -verbose:gc»

In practice, «-verbose:gc» argument activates the recording of collection information. The log, by default, is saved to stdout and produces rows for all GC. Also specify sequential GC, using the «-XX: +UseSerialGC» argument, and set the heap sizes.

In practice, can support to detect a leak in a timely manner and configure application health metrics.

Examples of GC log activation can be found on the GitHub service.

How teams can fix memory leaks. Error correction methods

to address this problem, it is necessary first to consider the reason why it has arisen. Therefore, it is necessary to identify the type of leak and solve the problem based on its variety. For each types, there is a different scheme how for fix memory errors in Java:

Minimize the use of static fields in the system. In this case, instead of urgent loading of objects – you can use the «lazy» one.

If there are internal classes, with reference to external:

You can convert an internal class to a static class if it does not need external class elements.

If the resources of the application are not closed:

«finally» should be activated in a timely manner to complete the use of resources.

Should lower to zero any work with finalists.

Try to upgrade the Java app to the latest version. This can work by moving the pool of strings to the free place of the heap, after the 6th version. And to avoid the error «Out Of Memory Error», in work with bulk strings you can extend the «PermGen» size.

Stable cleaning of ThreadLocal variables when they are not needed. ThreadLocal that has the remove() property – removes variable values for all current threads. It must be closed in the «finally» block to maintain that it is deactivated.

When implementing incorrect equals() and hashCode()

When creating new elements, it is always optimal to override the equals() and hashCode() path.

Other ways to eliminate memory leaks

You can also apply other methods to combat memory leaks when there is no clear understanding of the reason for their occurrence.

For a detailed analysis of code performance in Java, you can use its testing with benchmarking. In this way, it's easy to assess the productivity of different ways of performing tasks by comparing their effectiveness. This gives preference to best practices, which will avoid unnecessary memory consumption.

In practice, option of applying special reference objects in Java instead of direct references to elements in the application. The use of such links contained in the package «java.lang.ref» allows the simple removal of superfluous objects by the garbage collector.

Banal, but no less impactful in some cases method – checking the code. Sometimes it helps one time to eliminate memory leaks.

By using the above method, you can discover storage areas that can be usefully used to store application resources.

Another way mentioned earlier. Including this mode, we can closely monitor the work of GC.

Compliance with such rules of storage space and its rational use can support eliminate situations that create Java surges back up programming and Java surges back up language. This is the basis for the normal operation of the system as a whole.

  • Quest Foglight for Java (for heap monitoring);
  • MAT (for heap dump analysis).

As the expert on working with Java reports, on the portal Habr – a quote:

" After finding and fixing the leak, it will not be superfluous to go through all the steps again, analyze the memory, and report to the Memory Analyzer to make sure the fix helped."

For a clear understanding of memory bugs in Java, more information can be found here:

Putting it into practice

So, analyzing the question – what is memory leak in Java, it becomes clear that it affects the system as a disease that strikes it and worsens its overall condition. Without treatment, it can lead to irreparable consequences. And since this is a very serious problem, though not visible at first sight – it needs to be identified and addressed in a timely manner.

In practice, problem is not easily remedied if it is detected long after the first signs of its existence have emerged. There is no «magic pill» that will fix the leak once, even when involving the work of a highly qualified specialist in Java programming.

But if working with the app consistently involved the use of proven methods, profiling, tracking, Java memory management, and code verification – the appearance of such problems can be reduced to zero.

And have You ever encountered memory leaks in Java? Share your experience of identifying the type of problem and Your method of solving it in the comments!

Contact us to receive more information about memory leaks in Java and operative strategies for preventing them.

Moving from insight to delivery

Strong engineering outcomes depend on disciplined delivery: clear ownership, measurable milestones, and architecture that survives real-world load. Spectrum Future Tech works with enterprises that want that rigor without sacrificing speed — architect-led squads, transparent communication, and builds designed to scale.

Causes of a Memory Leak in Java. Problem Types and Ways to Fix Them | Spectrum Future Tech