<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: JillThornhill</title>
    <description>The latest articles on Forem by JillThornhill (@jillthornhill).</description>
    <link>https://forem.com/jillthornhill</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2975399%2Fb9387468-9f36-48f3-9473-8380032ec862.png</url>
      <title>Forem: JillThornhill</title>
      <link>https://forem.com/jillthornhill</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jillthornhill"/>
    <language>en</language>
    <item>
      <title>The Finalizer Problem: A Deeper Look into OutOfMemoryError Due to Unclosed Resources</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Fri, 23 Jan 2026 08:00:36 +0000</pubDate>
      <link>https://forem.com/jillthornhill/the-finalizer-problem-a-deeper-look-into-outofmemoryerror-due-to-unclosed-resources-3dn1</link>
      <guid>https://forem.com/jillthornhill/the-finalizer-problem-a-deeper-look-into-outofmemoryerror-due-to-unclosed-resources-3dn1</guid>
      <description>&lt;p&gt;The finalize() method of the Java class object, which can be overridden by any Java class, was deprecated as of Java 9. It will eventually be discontinued. Why?&lt;/p&gt;

&lt;p&gt;This article takes a look at exactly how the finalize() method works, when it’s run, and how badly things can go wrong. Using this method can result in unclosed resources, wasted Java heap space, and ultimately to OutOfMemoryErrors.&lt;/p&gt;

&lt;p&gt;Let’s see how this can happen, how to diagnose finalize() problems, and what we should do instead of using finalize().&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting OutOfMemoryError: Java Heap Space
&lt;/h2&gt;

&lt;p&gt;Before we start, if you’re not familiar with troubleshooting OutOfMemoryErrors, you may like to read this article: &lt;a href="https://blog.heaphero.io/java-outofmemoryerror-heap-space/" rel="noopener noreferrer"&gt;Java OutOfMemoryError: Heap Space&lt;/a&gt;. It gives some background into how to understand, find and fix memory issues.&lt;/p&gt;

&lt;p&gt;Another useful article on this topic deals with the 9 different types of &lt;a href="https://blog.heaphero.io/types-of-outofmemoryerror/" rel="noopener noreferrer"&gt;java.lang.OutOfMemoryError&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unclosed Resources
&lt;/h2&gt;

&lt;p&gt;Let’s now take a look at what we mean by unclosed resources.&lt;/p&gt;

&lt;p&gt;Examples of resources include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Heap and native memory;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;File Descriptors;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Operating system handles;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Network sockets;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database connections.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many classes that manage these resources, such as the Stream classes, have a close() method. This releases any associated resources. It’s important to call this method when the resources are no longer needed. If they don’t have one, we must ensure the objects are released for garbage collection in a timely manner.&lt;/p&gt;

&lt;p&gt;During the early years of Java, we were told that it was good practice to include these cleanup operations in a finalize() method, which would ensure all resources were released when the object was garbage collected.&lt;/p&gt;

&lt;p&gt;Fairly soon, this was found to be unreliable, as we’ll see in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  When is finalize() Executed?
&lt;/h2&gt;

&lt;p&gt;To keep redundant memory from building up, a JVM process known as the garbage collector (GC) runs in the background. On each cycle, it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Works from GC roots to identify and mark all memory items that still have live references;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For each unmarked item, the GC marks it as finalizable. If it has a finalize method, it’s added to the finalize queue; if not, GC marks it as eligible for deletion.;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Removes all objects eligible for deletion.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The JVM has a single finalize queue, which is not multi-threaded. It works sequentially through the queue, running the finalize() method of each object. Once the finalize() method has completed, the object is marked as eligible for deletion, and it will be removed on the next GC cycle.&lt;/p&gt;

&lt;p&gt;At best, an object that has a finalize() method, and all its children, remain in memory for two GC cycles instead of just one. If it has a large retained memory, this can be significant.&lt;/p&gt;

&lt;p&gt;It’s highly possible it will remain in memory for much longer. If a lot of objects are waiting to be finalized, it may be a while before they get to the front of the queue, and for all this time, they are retaining unneeded memory. This becomes more serious if a queued object is holding locks that may be needed by other processes, or unclosed resources.&lt;/p&gt;

&lt;p&gt;At worst, a single object in the queue may have a slow finalize() method, and the entire queue is held up until it completes. If it hangs waiting for a resource or a lock to be available, it can result in a memory leak and, eventually, an OutOfMemoryError.&lt;/p&gt;

&lt;p&gt;The other danger with using the finalize() method is that it may, in fact, never be executed at all. The object may still be in the queue when the program exits. If finalize() was used for important actions, such as database commits, this could result in data loss.&lt;/p&gt;

&lt;p&gt;The bottom line is: the developers of the JVM cannot guarantee when, or even if, the finalize() method will be run. It’s therefore been recognized as dangerous, and that’s why it has been deprecated.&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Diagnose Finalizer Problems
&lt;/h2&gt;

&lt;p&gt;Let’s take a small sample program that demonstrates the effect of slow finalizers. This application creates several instances from a class, BuggyClass, that deliberately has a hanging finalizer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This demonstrates a hanging finalizer, and how it causes memory to be retained
// even though a weak reference is used.
// ==============================================================================
import java.lang.ref.WeakReference;

public class BuggyProg {
// Public class creates an object from TestClass
// =============================================
    public static void main(String[] args) {
    TestClass a = new TestClass();
    }
}

// Test class creates a number of instances of BuggyClass using weak references


class TestClass {

   public TestClass() {
       WeakReference&amp;lt;BuggyClass&amp;gt; a=null;
       WeakReference&amp;lt;BuggyClass&amp;gt; b=null;
       WeakReference&amp;lt;BuggyClass&amp;gt; c=null;
       WeakReference&amp;lt;BuggyClass&amp;gt; d=null;
       WeakReference&amp;lt;BuggyClass&amp;gt; e=null;
       WeakReference&amp;lt;BuggyClass&amp;gt; f=null;
       WeakReference&amp;lt;BuggyClass&amp;gt; g=null;
       WeakReference&amp;lt;BuggyClass&amp;gt; h=null;
       WeakReference&amp;lt;BuggyClass&amp;gt; i=null;

       methodA(a);
       methodA(b);
       methodA(c);
       methodA(d);
       methodA(e);
       methodA(f);
       methodA(g);
       methodA(h);
       methodA(i);
       try 
              {Thread.sleep(150000);}
       catch (Exception ex){}
    }
    public void methodA(WeakReference a) {
         a = new WeakReference&amp;lt;BuggyClass&amp;gt;(new BuggyClass());
    }
}

// BuggyClass creates a large array, and has a hanging finalizer
// It prints a message to indicate when the finalize method is run
// ===============================================================
class BuggyClass {
   int[] a = new int[2000000];
   public BuggyClass() {
   }

   public void finalize() {
     System.out.println("Finalizing");
     while(true)  
        a[1]=100;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This program creates several instances of the class BuggyClass, which is released very quickly for garbage collection. This is because they’re created with weak references.&lt;/p&gt;

&lt;p&gt;BuggyClass deliberately has a finalizer that hangs. It displays a message ‘Finalizing’ when the finalizer runs.&lt;/p&gt;

&lt;p&gt;Let’s see what happens when we run the program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;c:\javadev\articles\demos&amp;gt;java BuggyProg
Finalizing

c:\javadev\articles\demos&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite the fact that we created multiple instances of BuggyClass, and made them available for GC, only ONE of these finalize() methods has been initiated. This is because the other instances were still waiting in the finalizer queue when the program completed. They will never be run at all.&lt;/p&gt;

&lt;p&gt;So how can we tell if we have objects waiting in the finalizer queue?&lt;/p&gt;

&lt;p&gt;The easiest way is to &lt;a href="https://blog.heaphero.io/how-to-capture-java-heap-dumps-7-options/" rel="noopener noreferrer"&gt;take a heap dump&lt;/a&gt;, and run the &lt;a href="http://heaphero.io" rel="noopener noreferrer"&gt;HeapHero&lt;/a&gt; tool. This produces a comprehensive heap analysis report, including an interactive section that lists the finalizer queue. We can drill down from this section to see the actual classes of objects awaiting finalization, as per the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fer2lle0hw1cn9omb1253.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fer2lle0hw1cn9omb1253.png" alt=" " width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Fig: Finalizer Report by HeapHero&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What Should We Use Instead of finalize()?&lt;/p&gt;

&lt;p&gt;When we create our own classes, we should use a close() method instead of finalize() for any cleanup operations. Of course, we need to document the fact that any application using this class must use this method to release resources.&lt;/p&gt;

&lt;p&gt;When we use other classes, we should always check if they have a close() method, and call it when the task is completed.&lt;/p&gt;

&lt;p&gt;Alternatively, we can use the &lt;a href="https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html" rel="noopener noreferrer"&gt;try-with-resources construct&lt;/a&gt; to automatically release resources when the block completes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The finalize() method has been deprecated with good reason. It can cause hard-to-find problems with Java heap space, as well as other issues such as running out of available file descriptors. Instead, we should put any cleanup code into a close() method.&lt;/p&gt;

&lt;p&gt;We also need to be meticulous about calling the close() method of resource-hungry classes such as streams, and ensure all our objects are released for garbage collection as soon as we’ve finished with them.&lt;/p&gt;

&lt;p&gt;The HeapHero tool is ideal for diagnosing finalizer problems, since it contains an explicit list of any objects in the finalizer queue.&lt;/p&gt;

</description>
      <category>java</category>
      <category>troubleshooting</category>
      <category>outofmemory</category>
      <category>finalizer</category>
    </item>
    <item>
      <title>Avoiding "Out of Memory" Errors: Strategies for Efficient Heap Dump Analysis</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Wed, 10 Dec 2025 16:26:11 +0000</pubDate>
      <link>https://forem.com/jillthornhill/avoiding-out-of-memory-errors-strategies-for-efficient-heap-dump-analysis-4287</link>
      <guid>https://forem.com/jillthornhill/avoiding-out-of-memory-errors-strategies-for-efficient-heap-dump-analysis-4287</guid>
      <description>&lt;p&gt;Most of us have seen this unwelcome exception in Java: &lt;em&gt;java.lang.OutOfMemoryError&lt;/em&gt;. In testing, this is annoying. In production, it can be disastrous.&lt;/p&gt;

&lt;p&gt;In live systems, we’re likely to see degraded performance followed by an OutOfMemory crash. The repercussions can include unhappy customers, overwhelmed support staff, loss of revenue and shouting managers. This is not anyone’s idea of a happy day.&lt;br&gt;
Can OutOfMemoryErrors be avoided? How?&lt;/p&gt;

&lt;p&gt;This article answers those questions.&lt;/p&gt;

&lt;p&gt;Too many administrators just increase the heap size haphazardly. Instead, we’ll look at how to use a memory analyzer throughout the project lifecycle to make informed decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Shouldn’t We Just Increase Heap Size?
&lt;/h2&gt;

&lt;p&gt;Here are a few good reasons why simply increasing the heap size is not a good idea.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If we have a memory leak, increasing the size will be at best a very temporary solution, since memory usage will eventually exceed the new limit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not all memory problems relate to the heap.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increasing the heap size may result in depriving other areas of the JVM, or even the device as a whole, of memory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Several other factors, such as the choice of garbage collection algorithms, could be the root cause of the problem. Increasing the heap size would not solve these problems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, what’s the solution?&lt;/p&gt;

&lt;p&gt;Firstly, if the heap runs out of memory, we need to use a heap dump analyzer such as &lt;a href="http://heaphero.io" rel="noopener noreferrer"&gt;HeapHero&lt;/a&gt; or &lt;a href="https://eclipse.dev/mat" rel="noopener noreferrer"&gt;Eclipse MAT&lt;/a&gt; to examine the heap and discover the cause of the problem. Only then can we figure out how to solve the real problem and prevent it from recurring.&lt;/p&gt;

&lt;p&gt;But more importantly, we need to proactively prevent memory problems by making performance analysis an integral part of each phase of the software lifecycle.&lt;/p&gt;

&lt;p&gt;Using Memory Analyzers Throughout the Project Lifecycle.&lt;/p&gt;

&lt;p&gt;Don’t wait until it breaks.&lt;/p&gt;

&lt;p&gt;Let’s see how we can use memory analyzers, and other diagnostic tools, to make sure we never encounter another java.lang.OutOfMemoryError in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Planning Stage
&lt;/h3&gt;

&lt;p&gt;Innovative ideas are great. However, all great inventors build prototypes, because it’s seldom possible to predict how things will actually work in real life.&lt;/p&gt;

&lt;p&gt;It’s good to get into the habit of building a small trial program to see how much memory we might need to implement our designs. This is especially important if we’re designing for small devices, or for containers. Also, if we’re designing for the cloud, memory usage has a direct impact on monthly running costs.&lt;/p&gt;

&lt;p&gt;This is where tools like HeapHero come in. While the program is running, we would dump the heap, as described in these articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.heaphero.io/2017/10/13/how-to-capture-java-heap-dumps-7-options/" rel="noopener noreferrer"&gt;Obtaining Heap Dumps in Windows, Linux and MacOS.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.heaphero.io/how-to-capture-heap-dump-from-android-app-3-options" rel="noopener noreferrer"&gt;Obtaining Heap Dumps in Android&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can then explore the heap using a heap dump analyzer. You may like to watch this video to see a demonstration of how to &lt;a href="https://www.youtube.com/watch?v=qDn08P-MIqQ" rel="noopener noreferrer"&gt;analyze a dump with HeapHero&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This takes the guesswork out of design, and lets us evaluate different strategies and make trade-offs as needed. It also gives us a good idea of how much memory the final solution may require, so we can accurately specify the hardware and carry out a cost-benefit analysis.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Development Stage
&lt;/h3&gt;

&lt;p&gt;At the development stage, we can use a memory analyzer in many ways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Comparing different coding techniques for efficiency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Checking for &lt;a href="https://blog.heaphero.io/how-much-memory-is-my-application-wasting" rel="noopener noreferrer"&gt;memory wastage&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Confirming that actual memory requirements match the original hardware specifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Providing memory usage statistics in order to accurately configure the heap size at the testing stage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. The Testing Stage
&lt;/h3&gt;

&lt;p&gt;At each phase of testing, we should use a memory analyzer to confirm that memory usage is reasonable, that we have no memory leaks, and obtain more accurate memory usage statistics.&lt;/p&gt;

&lt;p&gt;When we come to testing the system as a whole, and particularly in performance labs and stress tests, we should also look at monitoring &lt;a href="https://blog.gceasy.io/what-is-java-garbage-collection" rel="noopener noreferrer"&gt;garbage collection (GC) behavior&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Efficient GC is critical for preventing memory problems. We can use a GC log analysis tool such as &lt;a href="http://gceasy.io" rel="noopener noreferrer"&gt;GCeasy&lt;/a&gt; to make sure the GC is doing its job, and that memory is staying well within configuration limits.&lt;/p&gt;

&lt;p&gt;We can also recognize memory leaks and other potential memory issues by &lt;a href="https://blog.gceasy.io/interesting-garbage-collection-patterns" rel="noopener noreferrer"&gt;analyzing GC patterns&lt;/a&gt;. For example, the image below compares the pattern of a healthy application to one with a memory leak. In the memory leak pattern, although GC is clearing some memory on each cycle, it never manages to fully clear it back to the same level. If the memory leak is not resolved, usage will keep growing until we run out of heap memory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxx82b4xxufs5d7xivoiz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxx82b4xxufs5d7xivoiz.png" alt=" " width="756" height="990"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Fig: Memory Usage Graphs from GCeasy: Healthy Application vs Memory Leak&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we begin performance lab testing, we should think about automating some aspects of memory monitoring, and setting alerts if any problems are detected. There are two ways we can do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Both HeapHero and GCeasy offer &lt;a href="https://www.youtube.com/watch?v=hsqsD5c4nP0" rel="noopener noreferrer"&gt;REST APIs&lt;/a&gt; that can be included in testing scripts to automatically analyze the heap dump and the GC logs. They return key information that can be used to flag any issues found.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can use a monitoring and analysis system such as &lt;a href="http://ycrash.io" rel="noopener noreferrer"&gt;yCrash&lt;/a&gt;. This tool samples the JVM regularly to analyze &lt;a href="https://blog.ycrash.io/9-micro-metrics-that-forecast-production-outages-in-performance-labs" rel="noopener noreferrer"&gt;micrometrics&lt;/a&gt; that predict any developing performance issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By including performance analysis in our testing, we can identify and fix any bottlenecks, and also provide detailed statistics that can be used for accurate configuration in the live system.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Preparing to Go Live
&lt;/h3&gt;

&lt;p&gt;At this stage, we should use memory statistics produced during testing to accurately configure the heap.&lt;/p&gt;

&lt;p&gt;We should also set in place monitoring procedures for the live system, so that we will be alerted if performance indicators begin to drop.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. In Production
&lt;/h3&gt;

&lt;p&gt;Monitoring heap dump usage and GC logs regularly can prevent problems escalating to the point where performance is affected. System usage is likely to grow with time. If we see memory usage increasing, we can alter the JVM configuration to cater for growth.&lt;/p&gt;

&lt;p&gt;GC logging should always be enabled in production, as it uses very little overhead. We can then periodically submit logs to a GC log analyzer.&lt;/p&gt;

&lt;p&gt;We could set up heap dump extract and analysis as a CRON job that runs periodically. This shouldn’t happen too often, because dumping the heap can take time and reduce performance. It should be scheduled off-peak.&lt;/p&gt;

&lt;p&gt;Alternatively, we can set up the yCrash monitor to continuously sample performance, and raise alerts as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. In CI/CD Pipelines
&lt;/h3&gt;

&lt;p&gt;Incorporating HeapHero and GCeasy REST APIs into the build pipeline is an effective way to prevent new versions introducing memory issues.&lt;/p&gt;

&lt;p&gt;We can use them to automatically compare performance indicators with previous builds, and fail the build if we detect unacceptable changes.&lt;/p&gt;

&lt;p&gt;The indicators we can monitor include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt; Object Creation Rate;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Heap size;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Class Count;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Object count;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Throughput;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt; Latency;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Memory Wastage Percentage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We’ve looked at incorporating memory analyzers in all stages of the project lifecycle.&lt;/p&gt;

&lt;p&gt;Using this strategy, we can either increase the heap size or optimize the code long before issues result in an OutOfMemoryError. Even if we haven’t done this with existing systems, it’s never too late to start. Including memory monitoring, both in production and in future development cycles, saves a lot of heartache.&lt;/p&gt;

&lt;p&gt;Prevention is definitely better than cure.&lt;/p&gt;

</description>
      <category>java</category>
      <category>outofmemoryerror</category>
      <category>troubleshooting</category>
      <category>performance</category>
    </item>
    <item>
      <title>Don't Just Find the Leak, Fix the Root Cause: A Modern Approach to Memory Analysis</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Tue, 16 Sep 2025 08:10:18 +0000</pubDate>
      <link>https://forem.com/jillthornhill/dont-just-find-the-leak-fix-the-root-cause-a-modern-approach-to-memory-analysis-17gi</link>
      <guid>https://forem.com/jillthornhill/dont-just-find-the-leak-fix-the-root-cause-a-modern-approach-to-memory-analysis-17gi</guid>
      <description>&lt;p&gt;Your Java application has memory issues: maybe it’s throwing OutOfMemoryErrors, or maybe you’re experiencing degraded performance or frequent timeouts. You suspect a memory leak, and your heap dump analyzer has identified a few leak suspects in the Java heap space.&lt;br&gt;
What next?&lt;/p&gt;

&lt;p&gt;In this article we’ll look at some typical coding issues that result in memory leaks, and how to find and fix the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Memory Leak?
&lt;/h2&gt;

&lt;p&gt;A memory leak occurs when a program unnecessarily allocates more and more memory over time. Eventually, the program slows down and finally throws an OutOfMemoryError.&lt;/p&gt;

&lt;p&gt;Not all memory problems are leaks: they could be caused by either wasted memory, under-configuring the heap or other memory pools, or lack of RAM in the device or container. The best way to tell if the problem is a memory leak is to analyze the behavior of the garbage collector (GC).&lt;/p&gt;

&lt;p&gt;The graphs below were produced by &lt;a href="https://gceasy.io" rel="noopener noreferrer"&gt;GCeasy&lt;/a&gt;, a GC log analyzer, showing heap usage over time. The red triangles indicate full GC events. The first graph shows a healthy GC pattern, whereas the second indicates a memory leak.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9eagjqpy6l9x8a4ohrau.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9eagjqpy6l9x8a4ohrau.png" alt="Healthy GC Pattern vs Memory Leak" width="800" height="1048"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Fig: Healthy Memory Pattern vs Memory Leak Pattern&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Notice that, although the GC is freeing memory, heap usage continues to increase over time, and the GC runs more and more frequently. As time goes on, GC events run back-to-back in an attempt to clear memory, and performance degrades drastically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do All Memory Leaks Occur in the Java Heap Space?
&lt;/h2&gt;

&lt;p&gt;The majority of leaks affect the heap. For a debugging guide for heap memory issues, see this article: &lt;a href="https://blog.heaphero.io/java-outofmemoryerror-heap-space/" rel="noopener noreferrer"&gt;Java OutOfMemoryError: Heap Space&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s also possible for other areas, such as the metaspace or the direct buffer space, to suffer from memory leaks. In fact, there are &lt;a href="https://blog.heaphero.io/types-of-outofmemoryerror/" rel="noopener noreferrer"&gt;nine different types of OutOfMemoryErrors in Java&lt;/a&gt;. We can distinguish the type of error by examining the error message.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do We Troubleshoot OutOfMemoryErrors?
&lt;/h2&gt;

&lt;p&gt;To effectively find memory leaks we need to examine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The error message, to determine the error type;&lt;/li&gt;
&lt;li&gt;Garbage Collection logs, which can be analyzed by a tool such as &lt;a href="//gceasy.io"&gt;GCeasy&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;A heap dump, which can be analyzed by a dump analyzer such as &lt;a href="//heaphero.io"&gt;HeapHero&lt;/a&gt; or Eclipse MAT;&lt;/li&gt;
&lt;li&gt;The stack trace, which is displayed after the error message. This shows the line at which the error occurred, followed by the path the program took to reach that point.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The error message tells us which area of the JVM memory has run out of space. The GC logs indicate whether the issue is a memory leak, or just excess memory usage. If the problem lies with the Java heap space, we can use a heap dump analyzer to find and trace the ownership of the largest objects in memory. &lt;/p&gt;

&lt;p&gt;For a demonstration of how to do this, it’s worth watching this video:  &lt;a href="https://www.youtube.com/watch?v=qDn08P-MIqQ" rel="noopener noreferrer"&gt;How to Analyze a Heap Dump Fast&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Finally, working back through the stack trace helps us locate the offending code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Typical Causes of Memory Leaks and How to Fix Them
&lt;/h2&gt;

&lt;p&gt;In this section, we’ll look at a few of the causes of memory leaks, with hints on how to fix the code. Most, though not all, leaks will fit into these categories. &lt;/p&gt;

&lt;h3&gt;
  
  
  1. Forever-growing Object
&lt;/h3&gt;

&lt;p&gt;This is one of the two most common symptoms of memory leaks. A collection or cache continues to grow over time, until it causes memory problems. Causes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The program is not preventing duplicates from being stored. Make sure a proper policy is in place to prevent duplicates.&lt;/li&gt;
&lt;li&gt;The program doesn’t have a policy to evict older records from a cache, so the cache continually grows over time.&lt;/li&gt;
&lt;li&gt;A program loop is not terminating when it should, and contains code to add to a collection or cache. Use the stack trace to identify the loop, and ensure proper conditions are in place to make sure it terminates, even under unexpected conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Proliferation of Same Type of Objects
&lt;/h3&gt;

&lt;p&gt;This is the second most common symptom of leaks. The heap dump analysis will show a very large number of the same class of object. The causes can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Objects are not being released to the garbage collector when they’re no longer needed. This may be because they’re defined in the wrong scope, because they are not set to null after use, or because the program fails to call the close() method on objects that have one.&lt;/li&gt;
&lt;li&gt;The program is creating a large number of threads that don’t terminate;&lt;/li&gt;
&lt;li&gt;Objects aren’t being re-used;&lt;/li&gt;
&lt;li&gt;The program uses a large number of string concatenations. This creates new strings each time. It’s better to use the StringBuffer() class, which allows strings to be edited within a single object.&lt;/li&gt;
&lt;li&gt;The program is looping without a proper termination condition.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Slow finalize() Methods
&lt;/h3&gt;

&lt;p&gt;This is a less common cause of memory leaks. In fact, the finalize() method has been deprecated in later versions of Java, because it’s unreliable. &lt;/p&gt;

&lt;p&gt;If you’re analyzing the dump with HeapHero, it includes a list of objects awaiting finalization.&lt;/p&gt;

&lt;p&gt;When an object that has a finalize() method is eligible for garbage collection, the method is placed in the finalizer queue. This queue is single-threaded, so if this method is slow or hangs, none of the objects behind it in the queue can be garbage collected until it completes. This could be because it’s waiting for I/O or some other resource. To solve this issue, include a close() method in classes rather than a finalize() method.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Mutated keys in collections.
&lt;/h3&gt;

&lt;p&gt;This is an obscure and hard-to-debug cause of memory leaks. Collections such as HashMaps use the key to determine the bucket where an entry is stored, and if the key is changed, the map is unable to find the entry. It therefore doesn’t protect against duplicates, and doesn’t successfully delete entries. To prevent this, always use the final modifier on variables used as keys so they can’t be changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Uncleared ThreadLocal Variables
&lt;/h3&gt;

&lt;p&gt;This is another unusual and difficult-to-find error. &lt;a href="https://dev.tourl"&gt;ThreadLocal &lt;/a&gt;variables are used to associate a state with a thread. If they’re not cleared, and the thread doesn’t terminate for some time, these variables can build up in memory. &lt;/p&gt;

&lt;p&gt;This is particularly likely to happen when we're using thread pools.&lt;/p&gt;

&lt;p&gt;To fix this, either ensure threads terminate as they should, or use the remove() method of the variable to free it.&lt;/p&gt;

&lt;p&gt;Here are blogs that highlight the &lt;a href="https://blog.heaphero.io/common-memory-leaks-in-java-how-to-fix-them/" rel="noopener noreferrer"&gt;Common Memory Leaks&lt;/a&gt;  and &lt;a href="https://blog.heaphero.io/not-so-common-memory-leaks-how-to-fix-them" rel="noopener noreferrer"&gt;Not-So-Common Memory Leaks in Java&lt;/a&gt; that can be used in  debugging and fixing memory leaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we’ve looked at how to find memory leaks, examined some of the common causes and included hints on how to fix them. &lt;/p&gt;

&lt;p&gt;If you’ve experienced different causes of memory leaks, it would be great if you’d share them in the comments section, so we can pool our knowledge.&lt;/p&gt;

&lt;p&gt;Thank you.&lt;/p&gt;

</description>
      <category>java</category>
      <category>memoryleak</category>
      <category>troubleshoot</category>
      <category>heapdump</category>
    </item>
    <item>
      <title>Solving OutOfMemoryError: Native Method Stack Trace Analysis</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Mon, 15 Sep 2025 17:51:28 +0000</pubDate>
      <link>https://forem.com/jillthornhill/solving-outofmemoryerror-native-method-stack-trace-analysis-1epn</link>
      <guid>https://forem.com/jillthornhill/solving-outofmemoryerror-native-method-stack-trace-analysis-1epn</guid>
      <description></description>
    </item>
    <item>
      <title>Beyond Leak Suspects: Advanced Techniques for Deep Dive Memory Leak Analysis</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Mon, 02 Jun 2025 14:16:17 +0000</pubDate>
      <link>https://forem.com/jillthornhill/beyond-leak-suspects-advanced-techniques-for-deep-dive-memory-leak-analysis-57cb</link>
      <guid>https://forem.com/jillthornhill/beyond-leak-suspects-advanced-techniques-for-deep-dive-memory-leak-analysis-57cb</guid>
      <description>&lt;p&gt;Memory leaks can cause havoc in production. If they don’t actually make the program crash, they can degrade response times and performance drastically.&lt;/p&gt;

&lt;p&gt;Most memory leaks can be found fairly easily with a good heap dump analyzer, since the tool instantly highlights memory leak suspects. This is a great starting point, but to troubleshoot elusive issues, we need to go a little deeper.&lt;/p&gt;

&lt;p&gt;This article discusses what we can do if the leak suspect chart doesn’t give us the answers we need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Memory Leak, and What is a Heap Dump?
&lt;/h2&gt;

&lt;p&gt;A memory leak occurs when unnecessary objects remain in memory, in spite of the best efforts of the garbage collector (GC). The diagram below shows the difference between a healthy GC memory pattern, and a pattern indicating a memory leak.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8pgr7ods51ofl41zubr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8pgr7ods51ofl41zubr.png" alt="Image description" width="756" height="990"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Fig: Healthy GC vs Memory Leak Pattern&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the first chart, GC is consistently bringing down memory usage. In the second, although GC temporarily reduces memory congestion, memory usage is building up over time, until the system becomes unresponsive and may finally crash.&lt;/p&gt;

&lt;p&gt;A memory dump is a snapshot of memory at a given moment. Since it’s a very large binary file, we need tools to analyze it for memory leaks. In this article, we’ll be using the popular &lt;a href="http://heaphero.io" rel="noopener noreferrer"&gt;HeapHero&lt;/a&gt;  to illustrate this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Object Reference Tree
&lt;/h2&gt;

&lt;p&gt;The best tools identify the largest objects in memory as leak suspects. This is because we’ll almost always find the cause of the leak by examining the top three or four biggest objects. Unfortunately, this may not instantly let us identify the actual cause of the leak.&lt;/p&gt;

&lt;p&gt;An object reference tree is a tree structure that records the parent and child objects of each item in the heap, as illustrated in the diagram below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ak14fyjlvvzzuhcaehm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ak14fyjlvvzzuhcaehm.png" alt="Image description" width="786" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Fig: Object Reference Tree&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can see that Object A created Objects B, C and D; Object B created Objects E and F; and Object D created Object G.&lt;/p&gt;

&lt;p&gt;The Retained Heap is the total heap space occupied by an object and its children. The Shallow Heap is the space occupied by the object on its own.&lt;/p&gt;

&lt;p&gt;If Object B is identified as a leak suspect, the problem may actually be found amongst its children, E and F. We can determine whether the problem is likely to be found in the object itself, or in its children, by comparing the size of the shallow heap to the retained heap.&lt;/p&gt;

&lt;p&gt;The problem could also be that its parent, Object A, is not releasing it once it’s no longer needed. To find the leak, we need to browse up and down the object reference tree. Fortunately, with HeapHero, this is simple.&lt;/p&gt;

&lt;p&gt;For a demonstration, see the video &lt;a href="https://www.youtube.com/watch?v=qDn08P-MIqQ&amp;amp;t=5s" rel="noopener noreferrer"&gt;Finding Memory Leaks with HeapHero&lt;/a&gt;. We can move up and down the object tree by requesting either incoming or outgoing references, as shown in the screenshot below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pzles3dx0y4fm84iqie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pzles3dx0y4fm84iqie.png" alt="Image description" width="800" height="458"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Fig: Scrolling Through the Object Reference Tree&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing a Heap Dump for Memory Leaks: Other Considerations
&lt;/h2&gt;

&lt;p&gt;We need to bear in mind that the memory leak may be outside of heap memory. For example, if a bug in the program causes a loop in a method that creates classes dynamically, we could cause an Out of Memory error in the Metaspace.&lt;/p&gt;

&lt;p&gt;The HeapHero report contains a class histogram, listing the number of instances of each class, as shown in the screenshot below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0dl7zs90jl0gccwbj4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0dl7zs90jl0gccwbj4a.png" alt="Image description" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Fig: Class Histogram&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this histogram, the class jdk.internal.ref.Cleaner has nearly four thousand instances, which could well be the symptom of a leak.&lt;/p&gt;

&lt;p&gt;Memory problems may not be an actual leak, but may simply be caused by inefficient code. Duplicate strings, poorly-planned collections and boxed numbers can all cause performance problems. The HeapHero tool reports on any inefficiencies it detects. In the report below, the program had an excessive number of duplicate strings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rpv7112zkk8zcwe26t2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rpv7112zkk8zcwe26t2.png" alt="Image description" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Fig: Duplicate Strings&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, the problem may simply be that either the heap or the GC may be incorrectly &lt;a href="https://blog.ycrash.io/jvm-arguments-master-sheet/" rel="noopener noreferrer"&gt;configured&lt;/a&gt;. If we’re satisfied that the program code is not the cause of the problem, we can consider increasing the heap size, or using a different GC algorithm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When analyzing a heap dump for memory leaks, HeapHero offers so much more than just identifying leak suspects. We can interactively browse the object reference tree, see ML suggestions for improvement, investigate the class histogram and check for wasted memory.&lt;/p&gt;

&lt;p&gt;Troubleshooting obscure memory leaks need no longer be a frustrating, time-consuming chore.&lt;/p&gt;

</description>
      <category>java</category>
      <category>memoryleak</category>
      <category>heapdump</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>Analyzing OutOfMemoryError: GC Overhead Limit Exceeded</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Thu, 24 Apr 2025 14:47:37 +0000</pubDate>
      <link>https://forem.com/jillthornhill/analyzing-outofmemoryerror-gc-overhead-limit-exceeded-4</link>
      <guid>https://forem.com/jillthornhill/analyzing-outofmemoryerror-gc-overhead-limit-exceeded-4</guid>
      <description>&lt;p&gt;In this article, we’ll be taking a look at the Java runtime error: &lt;code&gt;java.lang.outofmemoryerror: gc overhead limit exceeded&lt;/code&gt;. It’s a fairly common error, but it can be confusing, because the same program can throw either &lt;code&gt;java.lang.outofmemoryerror: gc overhead limit exceeded&lt;/code&gt;, or j&lt;code&gt;ava.lang.outofmemoryerror: java heap space&lt;/code&gt;. This can even happen when the program is running with exactly the same data.&lt;/p&gt;

&lt;p&gt;What causes the error? How can we fix it, and why does the same program sometimes alternate between two different error messages? Let’s look for some answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GC, and What Causes a Program to Crash With &lt;em&gt;java.lang.outofmemoryerror: gc overhead limit exceeded&lt;/em&gt;?
&lt;/h2&gt;

&lt;p&gt;Garbage Collection (GC) is a process that runs periodically within the JVM to clean up items in memory that are no longer needed. For a full description of GC, and how to tune it, read this article: &lt;a href="https://blog.gceasy.io/what-is-java-garbage-collection/" rel="noopener noreferrer"&gt;What is Java Garbage Collection&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;The error &lt;code&gt;java.lang.outofmemoryerror: gc overhead limit exceeded&lt;/code&gt; occurs when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GC is using 98% or more of the available CPU time, preventing the application from doing any actual work AND&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GC is releasing less that 2% of memory on each cycle AND&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This has happened consistently for the last 5 GC cycles.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In simple terms, this means GC is continually running, but not freeing a significant amount of memory. Application performance degrades dramatically, and the JVM aborts the program to prevent it hogging CPU time to no purpose.&lt;/p&gt;

&lt;p&gt;The reason it may alternate with throwing &lt;code&gt;java.lang.outofmemoryerror: java heap space&lt;/code&gt; is that in both cases, available memory is dangerously low. Depending on what else is happening on the machine, it’s a matter of chance which error is thrown first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Causes
&lt;/h2&gt;

&lt;p&gt;A few different issues may cause this error, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The application has a memory leak. Either unused memory is not released in a timely manner, or the program is looping on a method that uses a lot of memory;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Traffic has spiked;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The application has been moved to the production environment without carrying out adequate load testing;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The heap has not been configured large enough for the application’s needs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Troubleshooting Out of Memory Errors Affecting the Heap
&lt;/h2&gt;

&lt;p&gt;For these errors, we need to analyze:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GC efficiency;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Heap contents.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s worth obtaining and analyzing a GC log. A good tool for this is &lt;a href="http://gceasy.io" rel="noopener noreferrer"&gt;GCeasy&lt;/a&gt;. It helps determine whether the problem is likely to be caused by a memory leak, and whether GC is working correctly.&lt;/p&gt;

&lt;p&gt;Looking at graphs of memory freed on each GC cycle, we can see a definite pattern that indicates a memory leak.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw3fws2rsmbt4w5d07vm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw3fws2rsmbt4w5d07vm.png" alt="Image description" width="800" height="1049"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Fig: Comparing a healthy GC pattern with a memory leak pattern using GCeasy&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The diagram at the top shows a graph of GC functioning efficiently. Memory increases, but decreases back to the same level after each GC cycle.&lt;/p&gt;

&lt;p&gt;The bottom diagram shows a typical memory leak pattern. The GC is releasing some memory, but overall, memory usage keeps increasing with time.&lt;/p&gt;

&lt;p&gt;Next, we need to take a &lt;a href="https://blog.heaphero.io/2017/10/13/how-to-capture-java-heap-dumps-7-options/" rel="noopener noreferrer"&gt;heap dump&lt;/a&gt;. A heap dump is a snapshot of heap memory, holding details of each item. It includes both the parents and children of each object in the heap. We can analyze it to determine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What objects are occupying the most space?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What parts of the source code reference those objects?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The easiest way to do this is to use the &lt;a href="http://heaphero.io" rel="noopener noreferrer"&gt;HeapHero&lt;/a&gt; tool. This article, &lt;a href="https://blog.heaphero.io/java-outofmemoryerror-gc-overhead-limit-exceeded/" rel="noopener noreferrer"&gt;Java OutOfMemoryError: GC Overhead Limit Exceeded&lt;/a&gt;, contains a sample program that throws the error, and a detailed explanation of how to trace the problem using HeapHero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions
&lt;/h2&gt;

&lt;p&gt;Once we’ve identified the problem, we can decide on a solution. This may be one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Fix memory leaks;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increase the heap size using the JVM switches &lt;code&gt;-Xms&lt;/code&gt; (Initial size) and &lt;code&gt;-Xmx&lt;/code&gt; (Maximum size);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upgrade to a newer version of Java. GC is progressively more efficient in each new release;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tune GC.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;error java.lang.outofmemoryerror: gc overhead limit exceeded&lt;/code&gt; occurs when the heap is short of space, and may alternate with the error &lt;code&gt;java.lang.outofmemoryerror: java heap space&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To solve it, we need to analyze the heap, as well as looking at GC efficiency. We can then either fix the application, or increase memory limits.&lt;/p&gt;

</description>
      <category>java</category>
      <category>troubleshooting</category>
      <category>garbagecollection</category>
      <category>outofmemory</category>
    </item>
    <item>
      <title>Tuning OutOfMemoryError: Metaspace Size Problems</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Thu, 24 Apr 2025 09:12:14 +0000</pubDate>
      <link>https://forem.com/jillthornhill/tuning-outofmemoryerror-metaspace-size-problems-4igk</link>
      <guid>https://forem.com/jillthornhill/tuning-outofmemoryerror-metaspace-size-problems-4igk</guid>
      <description>&lt;p&gt;When it comes to tuning and troubleshooting memory issues in Java, many people think only of the Java heap. However, the metaspace is also an important consideration. Metaspace memory is managed separately from the heap. Issues in this area can lead to performance problems and even system crashes, such as &lt;code&gt;java.lang.outofmemoryerror: metaspace&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What is the metaspace? How do we troubleshoot and tune it? In this article, we’ll answer those questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Metaspace?
&lt;/h2&gt;

&lt;p&gt;First let’s review the JVM memory model. The diagram below shows the various memory pools. Some of these are managed by the JVM, whereas others are stored in native memory managed by the operating system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47kphbcvp9jf1etb2dor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47kphbcvp9jf1etb2dor.png" alt="Image description" width="800" height="333"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Fig: JVM Memory Model Showing the Metaspace&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The metaspace is marked in red. It was introduced in Java 8 to replace the JVM-managed permanent generation (permgen) space. The metaspace is held in native memory allocated by the operating system as needed. It’s held as a collection of metaspace chunks, which are contiguous sections of memory.&lt;/p&gt;

&lt;p&gt;The metaspace stores class definitions, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Name;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Byte code for each method;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Constants.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may also hold other information, such as string pools.&lt;/p&gt;
&lt;h2&gt;
  
  
  Causes of the Error: java.lang.outofmemoryerror: metaspace
&lt;/h2&gt;

&lt;p&gt;If the metaspace exceeds its size limit, the application will crash with the error: &lt;code&gt;java.lang.outofmemoryerror: metaspace&lt;/code&gt;. This is likely to be caused by either too many classes being created, or, in rare cases, by using too many class loaders.&lt;/p&gt;

&lt;p&gt;Why is an application likely to have too many classes? The reasons include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dynamic class loading, typically when using either &lt;a href="https://www.oracle.com/technical-resources/articles/java/javareflection.html" rel="noopener noreferrer"&gt;Java Reflection&lt;/a&gt; or &lt;a href="https://groovy-lang.org" rel="noopener noreferrer"&gt;Groovy Scripting&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extensive use of large 3rd-party libraries;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Memory leaks, which happen either because classes are not dereferenced when no longer in use, or because a method that creates classes is repeated without a valid termination condition.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Troubleshooting &lt;code&gt;java.lang.outofmemoryerror: metaspace&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;There are many ways of troubleshooting and monitoring metaspace usage. This article, &lt;a href="https://blog.gceasy.io/inspect-the-contents-of-the-java-metaspace-region/" rel="noopener noreferrer"&gt;How to Inspect the Contents of the Java Metaspace Region&lt;/a&gt;, covers several tools that provide useful information.&lt;/p&gt;

&lt;p&gt;From JDK 11 onwards, the following JDK command is a quick way to summarize metaspace usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jcmd &amp;lt;PID&amp;gt; VM.metaspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It gives details of class usage, non-class usage and totals.&lt;/p&gt;

&lt;p&gt;For a worked example, including a sample program and a step-by-step guide to troubleshooting with the &lt;a href="http://heaphero.io" rel="noopener noreferrer"&gt;HeapHero&lt;/a&gt; tool, read: &lt;a href="https://blog.heaphero.io/java-outofmemoryerror-metaspace/" rel="noopener noreferrer"&gt;Java Out of Memory: Metaspace&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tuning the Metaspace
&lt;/h2&gt;

&lt;p&gt;When we experience the error: &lt;code&gt;java.lang.outofmemoryerror: metaspace&lt;/code&gt;, the first step is to ensure there are no memory leaks. As shown in the article linked above, HeapHero is an excellent tool for identifying application errors that affect memory.&lt;/p&gt;

&lt;p&gt;If the program is running as it should, the next step is to make the metaspace bigger.&lt;/p&gt;

&lt;p&gt;The following JVM switches can be used to adjust the size:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;-&lt;code&gt;XX:MetaspaceSize=&amp;lt;size&amp;gt;&lt;/code&gt;: Sets the initial size of the metaspace;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-XX:MaxMetaspaceSize&amp;lt;size&amp;gt;&lt;/code&gt;: Sets the maximum size to which the metaspace is allowed to grow.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The metaspace is cleaned by the JVM’s garbage collector, but only during full GC events. When using dynamic classes, it may not be cleared quickly enough to avoid Out of Memory errors. We can tune the garbage collection by setting the maximum and minimum fill percentages at which GC is triggered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-XX:MaxMetaspaceFreeRatio=&amp;lt;percentage&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-XX:MinMetaspaceFreeRatio=&amp;lt;percentage&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good tool for analyzing the efficiency of the garbage collector is &lt;a href="http://gceasy.io" rel="noopener noreferrer"&gt;GCeasy&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Never leave the metaspace out of account when tuning and&lt;br&gt;
troubleshooting Java applications. You could find yourself experiencing poor&lt;br&gt;
performance in production, and application failures such as &lt;code&gt;java.lang.outofmemoryerror:metaspace.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In summary, the metaspace is a pool held in native memory.&lt;br&gt;
It’s primarily used for class definitions. You can tune its size and garbage&lt;br&gt;
collection policy using JVM runtime switches.&lt;/p&gt;

&lt;p&gt;HeapHero and GCeasy are great tools for troubleshooting&lt;br&gt;
issues in the metaspace.&lt;/p&gt;

</description>
      <category>java</category>
      <category>troubleshooting</category>
      <category>metaspace</category>
      <category>tuning</category>
    </item>
    <item>
      <title>Emerging Trends in Java Garbage Collection</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Sun, 30 Mar 2025 16:17:09 +0000</pubDate>
      <link>https://forem.com/jillthornhill/emerging-trends-in-java-garbage-collection-f2</link>
      <guid>https://forem.com/jillthornhill/emerging-trends-in-java-garbage-collection-f2</guid>
      <description>&lt;p&gt;Efficient garbage collection is essential to Java application performance. What worked well in 1995, when Java was first released, won’t cope with the high demands of modern computing. To stay ahead of the game, you need to make sure you’re using the best GC algorithm for your application.&lt;/p&gt;

&lt;p&gt;In this article, we’ll look at evolving trends in Java garbage collection, and take a quick look at what’s planned for the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Computing Trends
&lt;/h2&gt;

&lt;p&gt;Any software that stands the test of time must evolve to keep up with technology. To understand how and why GC has changed over the years, we must look at overall trends in IT.&lt;/p&gt;

&lt;p&gt;Hardware has progressively trended towards becoming smaller, cheaper, faster and more powerful. Multi-core CPUs have become the norm, and GPUs have taken over the load of graphics processing. In 1995, a typical PC had around 8MB of memory. Most laptops now have at least 8GB. Faster networks have enabled larger numbers of users to access IT systems directly.&lt;/p&gt;

&lt;p&gt;On the one hand, cloud computing, BigData and AI require huge memory and CPU capacities. On the other, smart devices and the IoT require small, ultra-efficient systems. Robotics, virtual reality and other real time processes need fast and consistent response times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evolution of Java Garbage Collection
&lt;/h2&gt;

&lt;p&gt;If you’re not yet familiar with how GC works, I recommend this article: &lt;a href="https://blog.gceasy.io/what-is-java-garbage-collection/" rel="noopener noreferrer"&gt;Java Garbage Collection.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initially, Java had a single, simple GC algorithm, suitable for the small memory sizes and single-core processors of that era. With today’s wide divergence in IT requirements, from the very large to the very small, it’s no longer one-size-fits-all. Java now has six different GC algorithms (or seven, if you count Epsilon, used only for benchmarking).&lt;/p&gt;

&lt;p&gt;Each was written with a particular purpose in mind, and most of them still have a place today. Let’s have a brief look at them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Serial:&lt;/strong&gt; The original algorithm. It’s single-threaded, and all GC is stop-the-world, resulting in high latency. You may still use it where the heap size is very small, or you’re running in a small container or small device where multi-cores are not available.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parallel:&lt;/strong&gt;  Added to take advantage of multi-cored CPUs in Java 5. It has much better throughput, but latency is high. It’s used in processes where latency is not important. Large batch processes may perform well with this algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CMS (Concurrent Mark Sweep):&lt;/strong&gt; Released in Java 4, it reduced latency by doing much of the work concurrently. It didn’t deal well with compaction, and was later discontinued.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;G1:&lt;/strong&gt; Released in Java 7 to provide a good balance between latency and throughput. The heap is divided into equal-sized regions, each collected separately. Most of the work is done concurrently. You can configure pause time goals, making it simple to tune. It has been the default since Java 8, and is usually the best choice if the heap size is less than 32GB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Z:&lt;/strong&gt; Introduced in Java 11, it aimed to provide low latency and good scalability. Almost all the work is done concurrently, and it can scale for heap sizes in terabytes. It’s ideal for cloud computing and BigData. Originally non-generational, it has had the option of generational GC since Java 21. This resulted in a huge improvement in performance, at the expense of a larger memory footprint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shenandoah:&lt;/strong&gt; Developed by Red Hat, it had much the same objectives as Z. It’s also good for very large heap sizes and applications requiring low latency.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future Planned Developments
&lt;/h2&gt;

&lt;p&gt;Developers are currently working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;More features for Z GC;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Throughput improvements for G1 GC;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Footprint reduction in all algorithms;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A new algorithm, N2GC, which is an extension of G1. Suitable for BigData and other large caches, it aims to reduce latency and fragmentation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monitoring and Tuning
&lt;/h2&gt;

&lt;p&gt;It’s a good idea to evaluate and compare at least two algorithms for high-performance applications. A great tool for evaluating GC efficiency is &lt;a href="http://gceasy.io" rel="noopener noreferrer"&gt;GCeasy,&lt;/a&gt; which instantly provides a range of analytical data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Java GC must follow general trends in computing to remain competitive. Coping with large heap sizes, and delivering low latency, are the key requirements today.&lt;/p&gt;

&lt;p&gt;The development team works continually to improve performance and cater for new trends. GC efficiency has improved enormously since Java 8. Upgrading to the latest version of Java gives significant performance gains.&lt;/p&gt;

</description>
      <category>java</category>
      <category>tuning</category>
      <category>garbagecollection</category>
      <category>trends</category>
    </item>
    <item>
      <title>Advanced Garbage Collection Techniques and Best Practices</title>
      <dc:creator>JillThornhill</dc:creator>
      <pubDate>Tue, 25 Mar 2025 14:13:15 +0000</pubDate>
      <link>https://forem.com/jillthornhill/advanced-garbage-collection-techniques-and-best-practices-m7c</link>
      <guid>https://forem.com/jillthornhill/advanced-garbage-collection-techniques-and-best-practices-m7c</guid>
      <description>&lt;p&gt;Cranky users, critical processes failing, robots going haywire: all these are typical of application performance issues. Performance monitoring and tuning are vital for smooth-running systems.&lt;/p&gt;

&lt;p&gt;In Java, garbage collection (GC) can often be the culprit if systems aren’t performing as they should. Even if GC is not to blame, GC logs can provide vital information about how systems are performing, and identify present and future bottlenecks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Java GC Techniques
&lt;/h2&gt;

&lt;p&gt;GC monitoring and tuning isn’t difficult, but you need to have a good understanding of how GC works and the JVM memory model.&lt;/p&gt;

&lt;p&gt;You’ll need to know how to obtain GC logs, analyze them and use the information to tune your JVM settings.&lt;/p&gt;

&lt;p&gt;You should also have a good understanding of the different GC algorithms available in Java. Each has its own strengths and weaknesses, and you need to choose the right algorithm for your application. &lt;/p&gt;

&lt;p&gt;Briefly, the GC algorithms are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Serial&lt;/strong&gt;: This was the original GC algorithm, and up until Java 4, it was the only one available. It used single-threading, and all other threads were paused during GC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel&lt;/strong&gt;: Introduced in Java 5, it used multithreading. Some tasks were performed concurrently with user threads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CMS (Concurrent Mark Sweep)&lt;/strong&gt;: This was experimental in Java 4, and performed many of the GC tasks concurrently with application threads. It was sometimes problematic, because it didn’t deal well with defragmentation. It was later deprecated and then discontinued.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;G1&lt;/strong&gt;: This is the default algorithm in later versions of Java. Much of the work is done concurrently, and it’s efficient in most cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Z&lt;/strong&gt;: This is refined from G1 to deal better with larger heap sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shenandoah&lt;/strong&gt;: Also similar to G1, with improvements for working with large heaps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Epsilon&lt;/strong&gt;: This is a do-nothing algorithm used purely for benchmarking other algorithms. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Obtaining GC Logs
&lt;/h2&gt;

&lt;p&gt;You can request GC logs by using arguments on the command line when invoking your Java program. These arguments changed with Java 9.&lt;/p&gt;

&lt;p&gt;For Java 8 and below, the arguments are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-XX:+PrintGCDetails -Xloggc:&amp;lt;gc-log-file-path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Java 9 and above, the argument is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-Xlog:gc*:file=&amp;lt;gc-log-file-path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Analyzing GC Logs
&lt;/h2&gt;

&lt;p&gt;GC logs are produced in text format, so it’s possible to read the file manually. However, they are usually very long, and it would be a time-consuming and difficult task.&lt;/p&gt;

&lt;p&gt;JDK tools such as &lt;code&gt;jstat&lt;/code&gt; and &lt;code&gt;jcmd&lt;/code&gt; are useful in analyzing logs. However, one of the best tools is &lt;a href="http://gceasy.io" rel="noopener noreferrer"&gt;GCeasy&lt;/a&gt;. This produces useful stats, graphs and charts within minutes, and also gives performance tuning recommendations.&lt;/p&gt;

&lt;p&gt;Key performance indicators that show whether garbage collection is working correctly include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Throughput&lt;/strong&gt;: The percentage of time spent on application tasks as opposed to GC tasks. For critical systems, you should aim at a throughput of at least 98%;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Latency&lt;/strong&gt;: The time during which the application threads are paused waiting for GC events to complete. You should look at both maximum and average latency times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Footprint&lt;/strong&gt;: Resources used by GC.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GC Logging Best Practices
&lt;/h2&gt;

&lt;p&gt;Here are a few tips for making good use of GC logs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Monitor your logs regularly to pick up any problems that are developing before they become a major issue. This is where tools such as GCeasy are invaluable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Always enable logs in production. If you have an issue, and logs aren’t enabled, it may be difficult to replicate the problem in order to solve it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Always monitor over a 24-hour period, so you can assess what’s happening during low and high traffic times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the right GC algorithm.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid using excessive GC logging arguments on the command line: for most purposes, the arguments shown in the previous section are sufficient.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid using log rotation. This can often result in losing the very log that you most need. Instead, suffix the GC log file name with %t, which adds a timestamp to the log name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a suitable tool such as GCeasy to analyze the logs, and pay attention to the results.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tuning the GC Algorithm
&lt;/h2&gt;

&lt;p&gt;Java includes a wide range of command line arguments that you can use to tune your applications. Once you’ve made informed decisions based on the GC logs, you can tweak your JVM settings in various ways, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Adjusting the heap size;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adjusting the size/ratio of spaces within the heap;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Controlling how quickly objects are promoted to the next heap space;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The percentage of used space at which GC is activated;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The number of concurrent and parallel GC threads;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enabling or disabling string deduplication;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Changing the GC algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There may be occasions where resources such as CPU cores and memory are insufficient, and must be upgraded. If this is the case, regular monitoring of the GC logs helps you to plan ahead and put solutions in place before performance is dangerously downgraded.&lt;/p&gt;

&lt;p&gt;You may also need to refactor your code to ensure memory is released in a timely manner. &lt;/p&gt;

&lt;p&gt;Each of the GC algorithms requires a different tuning strategy.  This article, &lt;a href="https://blog.gceasy.io/what-is-java-garbage-collection/" rel="noopener noreferrer"&gt;What is Java Garbage Collection?&lt;/a&gt; contains links to specific tuning guides for each algorithm, as well as in-depth information on how garbage collection works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A good understanding of Java garbage collection is essential for maintaining good performance, especially in critical systems.&lt;/p&gt;

&lt;p&gt;Simple tweaks to the garbage collector can result in huge performance gains at very little cost. If your application is running in the cloud, you could be paying for CPU and memory resources you wouldn’t actually need if your GC worked correctly.  Uber reduced their costs dramatically with a few changes to GC operations.&lt;/p&gt;

&lt;p&gt;If you need to up your performance tuning skills, you may like to look at this &lt;a href="https://blog.gceasy.io/jvm-performance-engineering-troubleshooting/" rel="noopener noreferrer"&gt;Performance Tuning and Troubleshooting Masterclass&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>performance</category>
      <category>tooling</category>
      <category>software</category>
    </item>
  </channel>
</rss>
