Heap memory — the dynamic memory allocation

General article on how a Heap memory works and role of a Garbage Collector in it!

Rupam Jha
JavaMadeTranquil
Published in
8 min readOct 17, 2020

--

Today while being interviewed as a candidate for a SDE II role in a reputed organization, I was asked a very simple yet another important question for what do you know about a heap memory and Garbage collection in Java? Although I was fairly able to explain the concept, a thought prevailed for letting you all know about what a heap memory is and what should you typically answer it like, when questioned in an interview!

Hello Comrades,

To begin with, irrespective of you being aware or unaware of what does Java Heap Memory actually functions like. I would like to draw your attention towards what is the functionality of a Heap memory and what is Memory management in Java? Memory management is basically a process of allocating new objects and removing the unused objects[using Garbage Collection] properly. Java has an automatic memory management called Garbage collector that works in background to clean up the unused or say unreferenced objects and keeps freeing up the memory. There is a huge amount of memory in JVM which is divided into the Stack and Heap memory.

Heap Memory segments

Why Heap memory! When it comes to dynamically allocating a memory, all that you got to think about is the heap memory. A heap memory is basically used for a dynamic memory allocation [i.e. the program can ‘request’ and ‘release’ memory from the heap segment whenever it is required] of Java objects and JRE classes at the runtime. Any new object is always been created in Heap memory and the references to this objects are stored in stack memory. The objects are given global access i.e. can be accessed from anywhere in the application. A memory allocated to the heap lives until one of the mentioned events occurs:

  • Program termination
  • Memory freed

The Heap memory is divided into the two main generations stated as Young generation and Old generation. The first part of the Young generation is called as Eden space and the second part is called as Survivor space consisting of Survivor I and Survivor II. As we understood the different segments present in Young generation, let us understand what is the purpose of these segments.

The Young generation:

The moment any new object is created, the object moves into the Eden space first. Now, if the application is heavy and creates an ample of objects, in this case the Eden memory gets filled up with objects, here the Garbage collector pops in and clears up all the unused objects and this process is termed as Minor GC. This Minor GC will further move all the survivor objects[the objects in Eden space which still holds reference] to the Survivor memory space. Minor GC has performed automatically on Young Generation to free up the memory space. As we have so many objects being created for so many classes, so when the no. of object increases, the memory in the Eden space also increases. Minor GC works at a faster rate hence takes lesser time to perform. The Objects that survived in the Young generation are now moved to the Old generation.

The Old generation:

As the Old generations starts getting filled up with all the survivor objects, the Major GC is triggered for freeing up the space by clearing the unused or unreferenced objects from the Old generation. The Major GC takes a lot of time to perform freeing up the space.

The PermGen [Permanent Generation]:

This is been discarded in JDK version 8 and above. The PermGen is a special heap space, separated from the main heap memory. All the static variables and constants that we create gets stored in Method area, and Method area is a part of PermGen. The disadvantage about the PermGen is that it holds very limited memory size and thus if this space is filled we get OutOfMemoryError. When the class loaders in PermGen is not Garbage collected adequately , it leads to Memory leakage.

Metaspace is the new memory space which has replaced the PermGen from JDK 8 onward. This grows its memory allocations automatically by default as per the requirement. The advantage of the metaspace in JDK 8 is that the garbage collector automatically triggers the removal of the dead classes once the class metadata reaches its maximum size, there by reducing the chances of throwing OutOfMemoryError.

The default size of the heap memory is 128MB on most of the 32 bit devices, but it varies from JVM to JVM. Java Heap Dump is a snapshot of Java Heap memory, useful to analyze or troubleshoot any memory leak in Java.

Note: The Garbage collector collects only those objects that are created using ‘new’ keyword. So if you have created any object without using the new keyword you can perform its cleanup in the finalize()method block. Finalize() method is invoked each time before the object is garbage collected.

The Garbage collector:

What is Garbage collection? It is a process of analyzing which objects are holding references and which objects are unused in Java Heap memory thereby deleting the unused objects. Garbage collector is considered as a Heart of Core Java.

The two primary measures of a GC performance are:

  • throughput: It is the percentage of total time not spent in garbage collection. It refers to the amount of productive task done by our application in a given period of time[ eg. no. of database queries that can be completed over a period of time, or no. of transactions completed].
  • pause-time[latency]: Also known as Stop-the- world-event, denotes how long an application pauses or say remains unresponsive due to Garbage collection operation being performed.

Note: Garbage collection is performed by a daemon thread called GC. This thread calls the finalize() method before object is garbage collected.

Daemon thread: These are low priority threads which runs intermittently in background for Garbage collection. Thread Scheduler schedules these threads when CPU is idle. These threads are service oriented threads as they serve all the other user threads. They get created before other user threads and die after all the user threads. JVM terminates itself when all the user threads are done with their execution, JVM does not care weather a daemon thread is still running or not, if JVM finds any running daemon thread(upon completion of the user threads), it terminates the daemon thread and after that shutdowns itself. All the user created threads are non-daemon threads and in order to make any thread as a daemon thread we use setDaemon() method.

Types of Garbage collector: To be very precised about the Garbage collector types, we have most commonly used ones as mentioned below:

  • Serial Garbage Collector
  • Parallel Garbage Collector[throughput collector]
  • CMS collector[Concurrent Mark Sweep]
  • G1 Garbage Collector[Garbage First]

Serial Garbage Collector: It is designed for a single threaded environment. Both the Minor GC and Major GC is done serially one after the other using single virtual CPU. It internally uses “Mark Compact Collection Algorithm”. It moves all the older memory to the beginning of the heap so that a new memory allocation are done in continuous chunk at the end of the Heap, which makes it faster to allocate new chunks of memory to the Heap.

Recommended to be used : Where multiple JVMs run over same machine[i.e. when JVM will run GC it will use only one processor to minimize the interference of the remaining JVMs]. When application runs on client style machines.

Parallel Garbage Collector: It is a default Garbage collector of JVM. It internally uses “Mark Compact Collection Algorithm”. It uses multiple threads to execute Minor GC thereby reducing serial execution time. Its similar to the Serial Garbage Collector except for that it uses multiple threads for Minor GC[parallel execution in Minor GC] and single thread for Major GC[serial execution for Major GC]

Recommended to be used: When an application can afford low pause time or application running on host with multiple CPUs.

Concurrent Mark Sweep Garbage Collector: It uses multiple threads to scan the Heap memory. CMS Garbage collector holds the application threads in two scenarios : while marking the referenced objects in tenured generation space or if there is a change in heap memory in parallel while doing the GC. It minimizes the pause time by doing most of the GC work concurrently with the application threads.It internally uses “Mark and Sweep Algorithm”. In Major GC, the CMS Garbage collector pauses all the application threads for a brief period of the time at the beginning of the collection and towards the middle of the collection; second pause being longer than the first one.

Recommended to be used: when application requires low Garbage Collection pause-time, when an application can afford to share processor resources with GC while application is still running and when an application has relatively a larger set of tenured generation and runs over a machine with 200 or more processors.

G1 Garbage Collector: It was primarily introduced in Java 7 to be a substitution for CMS Garbage Collector. G1 Garbage Collector is parallel[concurrent]and incremental compacting low pause-time Garbage collection. It offers customization so that user can give their preferred pause-times. It focuses on limiting the pause-time and maximizing the throughput. Its distinctive feature is that it divides the heap memory into many[unused, humongous, Eden, survivor,old generation] fixed sized regions[around 2000 regions whose size varies from 1- 32 MB] , there by giving greater flexibility in memory usage. It uses “Snapshot At The Beginning Algorithm”, which is faster than CMS.

Recommended to be used: for large heap memory areas, when rate of object allocation or promotion varies significantly, when long GC [>0.5 to 1 sec] is acceptable.

Some other GC types are:

Incremental low pause Garbage Collector, ParNew Garbage Collector, PS Scavenger and PS MarkSweep Garbage Collector

All you should know about the Automatic Garbage Collection: AGC is the process of identifying and deleting the unused objects in the heap memory. The process is split into marking and deleting of the unused objects. The AGC firstly marks which part of memory is in use and which is not. Before marking the objects are referred in blue coloration[stating they are in alive state]and after being marked they are in orange coloration[stating they are not in use anymore]. Once marking of all the objects are done, the process of deletion starts. The deletion process is further split into normal deletion and compact deletion. In normal deletion, the unreferenced objects are removed leaving the referenced objects and pointers to the freespace. The memory allocator holds the address of these pointers to freespace, so that new objects can be filled in here. The compact deletion improves the performance by removing all the unreferenced objects and moving all the referenced objects together so that new memory allocation becomes easier and faster.

Ending Note:

All the Java Object created using “new” keyword is created in Heap memory.

GC process automatically clears objects that are unused from the Heap in order to reclaim the Heap space; we just need to specify the type of GC at the JVM startup.

GC calls the finalize() method only once for an object.

We can force an early Garbage Collection using System.gc(). As System.gc() is called, the daemon threads in the background are given highest priority and perform Garbage Collection. It is the “aging threshold” which decides the moving of referenced objects from one generation to the other!

That is it on this article from my end. Hope it was of some help to you in better understanding what a Heap Memory is and how Garbage collection functions.

Until next time!

Peace Out!

Rupam Pawan Jha

--

--

Rupam Jha
JavaMadeTranquil

DevOps Engineer. Automation Enthusiast. Sharing my experiences on CI/CD, Docker, Kubernetes, and IaC.