<?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>DEV Community: Nimbleways</title>
    <description>The latest articles on DEV Community by Nimbleways (@nimbleways).</description>
    <link>https://dev.to/nimbleways</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%2Forganization%2Fprofile_image%2F4297%2F1e8ac01b-9e37-4176-a0d3-5386df29b479.png</url>
      <title>DEV Community: Nimbleways</title>
      <link>https://dev.to/nimbleways</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nimbleways"/>
    <language>en</language>
    <item>
      <title>A starting point to debug a Java OutOfMemoryError</title>
      <dc:creator>Adil Baaj</dc:creator>
      <pubDate>Tue, 17 Jan 2023 17:04:34 +0000</pubDate>
      <link>https://dev.to/nimbleways/a-starting-point-to-debug-a-java-outofmemoryerror-291k</link>
      <guid>https://dev.to/nimbleways/a-starting-point-to-debug-a-java-outofmemoryerror-291k</guid>
      <description>&lt;p&gt;A wise man once said, if you are a Java developer long enough you’ll eventually run into an OutOfMemoryError in production. This is the harsh fate that I met recently on a Spring Boot application I was working on.&lt;/p&gt;

&lt;p&gt;I wrote this article to share a few of my learnings while investigating this error. I believe this article is a good starting point to help you debug your OutOfMemoryError.&lt;/p&gt;

&lt;p&gt;So brace yourselves, fasten your seatbelts, and let’s dive right in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OutOfMemoryError is (basically) due to a lack of heap space&lt;/li&gt;
&lt;li&gt;Isolate the part of the code that triggers the issue using tools like MAT to analyse a heap dump, and either fix your code or increase the heap size&lt;/li&gt;
&lt;li&gt;Configure your JVM to make it deterministic and detect a potential OutOfMemoryError early&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This article was originally posted &lt;a href="https://blog.nimbleways.com/a-starting-point-to-debug-a-jvm-outofmemoryerror/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The mighty JVM
&lt;/h2&gt;

&lt;p&gt;To understand the root cause of the OutOfMemoryError, we first need to understand what the JVM is and how it is related to this error.&lt;/p&gt;

&lt;p&gt;In the 1990s, well before the rise of docker and containerisation, Java delivered one promise : write once, run everywhere.&lt;/p&gt;

&lt;p&gt;Java is a programming language that needs to be compiled. This is done by using the &lt;code&gt;javac&lt;/code&gt; utility, which generates bytecode. bytecode is code that is neither machine code nor human readable code, but something in between.&lt;/p&gt;

&lt;p&gt;The JVM (Java Virtual Machine)  is a piece of software that interprets this bytecode and turns it into machine code. Modern JVM implementations also offer AOT (Ahead Of Time) compilation capabilities to speed up the code execution. So although bytecode is not platform dependant, the JVM obviously is.&lt;/p&gt;

&lt;p&gt;The JVM is also responsible for memory management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources to go further:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.w3schools.in/java/java-virtual-machine" rel="noopener noreferrer"&gt;https://www.w3schools.in/java/java-virtual-machine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/jvm-works-jvm-architecture/" rel="noopener noreferrer"&gt;https://www.geeksforgeeks.org/jvm-works-jvm-architecture/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.eclipse.org/openj9/docs/introduction/" rel="noopener noreferrer"&gt;https://www.eclipse.org/openj9/docs/introduction/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Java memory management
&lt;/h2&gt;

&lt;p&gt;When you start a Java program, the JVM will reserve different memory areas for different purposes. The one that we are interested in is the heap area.&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%2Fqbmvgnphse66f8wxxyao.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%2Fqbmvgnphse66f8wxxyao.png" alt="Different JVM memory areas " width="722" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The heap is basically the part of the memory where the JVM will store the objects that you instantiate in your code. When an instantiated object is no longer needed, it is freed from memory by the garbage collector, which is managed by the JVM as well.&lt;/p&gt;

&lt;p&gt;So when does an OutOfMemoryError occurs ? When you no longer have enough free space to store a new object in the heap.&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%2Fznw7d8bol0i4o1c8fkzo.jpg" 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%2Fznw7d8bol0i4o1c8fkzo.jpg" alt="Bernie asking for memory" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources to go further :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/java-memory-management/" rel="noopener noreferrer"&gt;https://www.geeksforgeeks.org/java-memory-management/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/java-jvm-memory-model-memory-management-in-java" rel="noopener noreferrer"&gt;https://www.digitalocean.com/community/tutorials/java-jvm-memory-model-memory-management-in-java&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  OutOfMemoryError types
&lt;/h2&gt;

&lt;p&gt;Well, I lied. I told you that the OutOfMemoryError is cause by lack of heap space (and that actually is one of the OutOfMemoryError types). But the truth is there are other causes that could trigger an OutOfMemoryError. In this &lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks002.html" rel="noopener noreferrer"&gt;Oracle documentation&lt;/a&gt; they list (and explain the possible cause of) 7 types of errors :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;java.lang.OutOfMemoryError: Java heap space&lt;/li&gt;
&lt;li&gt;java.lang.OutOfMemoryError: GC Overhead limit exceeded&lt;/li&gt;
&lt;li&gt;java.lang.OutOfMemoryError: Requested array size exceeds VM limit&lt;/li&gt;
&lt;li&gt;java.lang.OutOfMemoryError: Metaspace&lt;/li&gt;
&lt;li&gt;java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?&lt;/li&gt;
&lt;li&gt;java.lang.OutOfMemoryError: Compressed class space&lt;/li&gt;
&lt;li&gt;java.lang.OutOfMemoryError: reason stack_trace_with_native_method&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also have a look at this &lt;a href="https://github.com/rangareddy/ranga-java-oom" rel="noopener noreferrer"&gt;repository&lt;/a&gt; with samples of code that trigger the different OutOfMemoryError types.&lt;/p&gt;

&lt;p&gt;In my case I encountered the &lt;code&gt;GC Overhead limit exceeded&lt;/code&gt; error. &lt;/p&gt;

&lt;p&gt;As per Oracle documentation :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The detail message "GC Overhead limit exceeded" indicates that the garbage collector is running all the time and Java program is making very slow progress. [...] This exception is typically thrown because the amount of live data barely fits into the Java heap having little free space for new allocations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's take a code sample that triggers this error, and see how to debug it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging an OutOfMemoryError 🧐
&lt;/h2&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%2Fib3qipbkjmigdkfkbaf2.jpg" 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%2Fib3qipbkjmigdkfkbaf2.jpg" alt="When I do Java, I do OoME" width="320" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are tools that can help you debug, from my research I found 3 interesting ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://visualvm.github.io/" rel="noopener noreferrer"&gt;VisualVM&lt;/a&gt; (free tool maintained by Oracle)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.eclipse.org/mat/" rel="noopener noreferrer"&gt;MAT&lt;/a&gt; (free open source software maintained by Eclipse Foundation)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ej-technologies.com/products/jprofiler/overview.html" rel="noopener noreferrer"&gt;Jprofiler&lt;/a&gt; (paid software)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are going to demonstrate the first two tools using the &lt;code&gt;GCOverheadLimitDemo&lt;/code&gt; from the the &lt;a href="https://github.com/rangareddy/ranga-java-oom" rel="noopener noreferrer"&gt;repository mentioned above&lt;/a&gt;. Let's say we want to generate 1.000.000 Employee objects and insert them into a database. We want to avoid inserting each object separately into the DB as each request is costly, and want instead to insert a list of Employee objects. Here is the corresponding code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GCOverheadLimitDemo.java&lt;/span&gt;
&lt;span class="c1"&gt;// JVM Parameters: -Xms10m -Xmx10m -XX:+UseParallelGC&lt;/span&gt;
&lt;span class="c1"&gt;// We limit the JVM Heap memory to 10MB&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.ranga.java.oom&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GCOverheadLimitDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// I added this line here to give me time to configure VisualVM&lt;/span&gt;
                &lt;span class="c1"&gt;// To monitor the JVM before the end of code execution&lt;/span&gt;
                &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(++&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ranga "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.05f&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nc"&gt;Employee&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Insert Employees into database here&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is the result of the execution of the above code:&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%2F18jolhlnvjmsc8dzod0x.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%2F18jolhlnvjmsc8dzod0x.png" alt="OoME is triggered" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring with VisualVM
&lt;/h2&gt;

&lt;p&gt;We are going to use VisualVM to monitor heap memory usage as well as the garbage collector activity.&lt;/p&gt;

&lt;p&gt;In order to do it we need to execute our code and tell VisualVM to monitor the corresponding JVM (pretty straightforward). Below is the result:&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%2F3uy2d19er92kefax1q2e.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%2F3uy2d19er92kefax1q2e.png" alt="VisualVM dashboard" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that right before the OutOfMemoryError was triggered, the GC activity peaked. Excessive GC activity triggered the &lt;code&gt;GC Overhead limit exceeded&lt;/code&gt; error and caused the code to crash.&lt;/p&gt;

&lt;p&gt;Next we need to isolate the part of the code that triggered this error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heap dump analysis with MAT
&lt;/h2&gt;

&lt;p&gt;On top of monitoring the JVM activity, you can also generate a heap dump when an OutOfMemoryError is triggered. A heap dump is basically a snapshot of the heap, it contains all the objects that were stored in the heap at the moment the dump was generated. The goal is to analyse further the data constituting the heap dump to get a hint on the actual code that triggers the OutOfMemoryError. In order to achieve this I added the following JVM parameter &lt;code&gt;-XX:+HeapDumpOnOutOfMemoryError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When the OOM exception occurs, it generates a &lt;code&gt;.hprof&lt;/code&gt; file. This file can be analysed using MAT. Note that before the heap is generated, a GC cycle is triggered and therefore the dump only contains live objects.&lt;/p&gt;

&lt;p&gt;Below is the result for  &lt;code&gt;GCOverheadLimitDemo&lt;/code&gt; example:&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%2F79kwkpaxzkmdvpbj6cjk.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%2F79kwkpaxzkmdvpbj6cjk.png" alt="MAT analysis of a .hprof file" width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can clearly see that the object that is taking most of heap space is an ArrayList of Employee objects. I can now look for places in my code where I instantiate such objects and either fix the part of the code responsible for the error (if relevant) or just increase the heap maximum size.&lt;/p&gt;

&lt;p&gt;In our case for example, if we don't want or can't increase the maximum heap size, we can insert Employee objects by batch of 10.000 instead of 1.000.000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.ranga.java.oom&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GCOverheadLimitDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++){&lt;/span&gt;

            &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// At the end of each loop, the initial list can be&lt;/span&gt;
            &lt;span class="c1"&gt;// Garbage collected, thus releasing memory&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ranga "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.05f&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="nc"&gt;Employee&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Insert Employees into database here&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Other tools to debug your OutOfMemoryError
&lt;/h2&gt;

&lt;p&gt;There are some other tools worth mentioning to monitor / help debug OOM exceptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html" rel="noopener noreferrer"&gt;spring-boot-actuator&lt;/a&gt; if you are running a Spring Boot backend (free)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/performissues.html" rel="noopener noreferrer"&gt;Java flight recorder&lt;/a&gt; (JFR) to register a JVM activity (free for non production usage only)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A deterministic JVM
&lt;/h2&gt;

&lt;p&gt;One important thing to consider before pushing your java application into production is your JVM settings. There are a lot of resources that list the most important parameters to configure, like &lt;a href="https://www.baeldung.com/jvm-parameters" rel="noopener noreferrer"&gt;this article&lt;/a&gt; or &lt;a href="https://docs.oracle.com/en/java/javase/19/gctuning/ergonomics.html#GUID-DB4CAE94-2041-4A16-90EC-6AE3D91EC1F1" rel="noopener noreferrer"&gt;Oracle documentation&lt;/a&gt;. I highly recommend to check it out before reading further.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt; it is considered best practice to at least configure: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The heap memory size using &lt;code&gt;-Xms&lt;/code&gt; (minimum heap size) and &lt;code&gt;-Xmx&lt;/code&gt; (maximum heap size) &lt;/li&gt;
&lt;li&gt;The garbage collector algorithm like &lt;code&gt;-XX:+UseParallelGC&lt;/code&gt; to use the parallel garbage collector algorithm for example&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's say you have an &lt;code&gt;app.jar&lt;/code&gt;  that you want to execute, you would use for example : &lt;code&gt;java -Xms10m -Xmx1G -XX:+UseParallelGC -j api.jar&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips and tricks
&lt;/h2&gt;

&lt;p&gt;Ideally one would detect an OutOfMemoryError way before the code is pushed to production. So here are a few tips to help you do that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure your JVM to use as little heap memory as possible, this will help you detect quickly the memory and / or performance bottlenecks starting from your local environment&lt;/li&gt;
&lt;li&gt;Be “iso production” in all your environments (including local environment), this means using in all your environments:

&lt;ul&gt;
&lt;li&gt;The same JVM / JDK versions&lt;/li&gt;
&lt;li&gt;The same configuration for the JVM&lt;/li&gt;
&lt;li&gt;The same volume of data (if for example you use a big database in production, use in other environments a database with equivalent amount of data)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Load test your code to simulate a production load (you can use tools like &lt;a href="https://k6.io/" rel="noopener noreferrer"&gt;k6&lt;/a&gt; or &lt;a href="https://gatling.io/" rel="noopener noreferrer"&gt;Gatling&lt;/a&gt;)&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;So we explored a few ways to debug an OutOfMemoryError when using Java code, as well as some tips to detect early a potential OutOfMemoryError. I wrote this article after facing myself the same situation in production within a Spring Boot backend. But obviously when working with such backends there are other performance challenges to tackle, like the infamous N+1 query problem. You can check &lt;a href="https://blog.nimbleways.com/using-entitygraphs-to-solve-n-1-query-problem/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; if you want to learn how to tackle N+1 query issues within a Spring Boot backend.&lt;/p&gt;

&lt;p&gt;Keep Javaing ☕️&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
  </channel>
</rss>
