Header Ads Widget

Responsive Advertisement

How work Garbage Collection in Java

Garbage Collection (GC) in Java is an automatic memory management process that reclaims memory by removing objects that are no longer in use, preventing memory leaks. Java's GC process is designed to track the life cycle of objects and ensure that unused objects are removed, thus freeing up memory for new objects.

Key Concepts of Java Garbage Collection

  1. Heap Memory:

Ø  The heap is where all the objects are allocated memory dynamically. It's divided into two main parts:

ü  Young Generation: Where newly created objects are placed.

ü  Old Generation: Where long-lived objects are stored.

  1. Garbage Collection Roots (GC Roots):

Ø  GC roots are special objects used as starting points for identifying live objects. Common GC roots include:

ü  Active Threads

ü  Static variables

ü  Local variables in method calls

ü  JNI references

  1. Reachability:

Ø  An object is considered "reachable" if it can be accessed through a chain of references from the GC roots. If an object cannot be reached, it is considered eligible for garbage collection.

  1. Mark and Sweep Algorithm:

Ø  Java's GC uses this algorithm to determine which objects are no longer used:

ü  Mark Phase: The GC marks all reachable objects.

ü  Sweep Phase: All unmarked objects (unreachable) are removed, and their memory is reclaimed.

Types of Garbage Collectors in Java

Java provides different types of garbage collectors with varying performance characteristics:

  1. Serial Garbage Collector:

Ø  A simple and basic GC that works in a single thread, pausing all application threads during garbage collection. It is suitable for small applications and is the default collector for single-threaded environments.

  1. Parallel Garbage Collector (Throughput Collector):

Ø  This collector uses multiple threads for both the young and old generation collections, minimizing GC pauses by performing the work in parallel. It is suited for applications requiring high throughput.

  1. CMS (Concurrent Mark-Sweep) Garbage Collector:

Ø  The CMS collector is designed to minimize application pauses by running the GC concurrently with the application. It uses multiple threads to perform garbage collection in the old generation and is suitable for applications requiring low-latency.

  1. G1 (Garbage First) Garbage Collector:

Ø  G1 is designed for larger heap sizes and performs collection in both the young and old generations concurrently. It divides the heap into regions and performs garbage collection based on regions with the most garbage. It is well-suited for multi-processor machines and applications that require predictable pauses.

  1. Z Garbage Collector (ZGC):

Ø  A low-latency GC designed for applications that need minimal GC pauses, even with large heaps. It performs most of the work concurrently with application execution.

  1. Shenandoah Garbage Collector:

Ø  Shenandoah is another low-latency garbage collector focused on reducing pause times by running concurrent phases for almost all GC steps.

Garbage Collection Algorithms

  1. Serial Garbage Collector:

Ø  Algorithm: Single-threaded and designed for small applications.

Ø  Process: All threads are stopped during garbage collection (Stop-the-World event). It marks, sweeps, and compacts memory using a single thread.

  1. Parallel Garbage Collector:

Ø  Algorithm: Multi-threaded version of the serial collector.

Ø  Process: Multiple threads are used for the marking and sweeping phase, improving throughput but still leading to stop-the-world pauses.

  1. Concurrent Mark-Sweep (CMS) Collector:

Ø  Algorithm: Concurrent collector for the old generation.

Ø  Process: It marks objects concurrently with application threads, minimizing pauses but can lead to heap fragmentation.

  1. Garbage First (G1) Garbage Collector:

Ø  Algorithm: Region-based collection.

Ø  Process: Divides the heap into regions, collecting those with the most garbage first. It can be concurrent and provides predictable pause times.

Ø  Compaction: After marking and sweeping, G1 may also compact memory to reduce fragmentation.

  1. Z Garbage Collector (ZGC):

Ø  Algorithm: Low-latency garbage collector.

Ø  Process: It performs most of its work concurrently with application threads, ensuring very short pauses, even with very large heap sizes.

 

mark and sweep algo
mark and sweep algo


 

Detailed Flow of GC:

  1. New Object Creation:

Ø  Objects are created in the Eden space of the young generation.

  1. Minor GC:

Ø  When Eden fills up, a Minor GC occurs. Reachable objects are moved to a survivor space, while unreachable objects are discarded.

  1. Promotion to Old Generation:

Ø  Objects that survive several Minor GCs are eventually promoted to the old generation.

  1. Major GC:

Ø  When the old generation fills up, a Major GC is triggered, which is more expensive but clears the old generation of unreachable objects.

 

Generations in Java Heap

  1. Young Generation:

Ø  This is where all new objects are allocated. It is divided into three areas:

ü  Eden Space: Where new objects are created.

ü  Survivor Space: Holds objects that survive one or more garbage collection cycles in Eden.

Ø  Minor GC: When Eden fills up, a minor GC occurs, moving surviving objects to the survivor spaces or promoting them to the old generation.

  1. Old Generation:

Ø  Objects that have lived long enough are promoted here. When this part of the heap becomes full, a Major GC (or Full GC) occurs, which is more expensive and can result in longer pause times.

Phases of GC in Java

  1. Minor Garbage Collection:

Ø  This collects garbage from the young generation. It is generally fast but happens frequently since the young generation fills up quickly.

  1. Major (or Full) Garbage Collection:

Ø  This collects garbage from both the young and old generations. It is a more expensive operation in terms of time because it involves more memory and often causes a stop-the-world event where all application threads are paused.

Important JVM Flags for Garbage Collection

Ø  -XX:+UseSerialGC: Enables the serial garbage collector.

Ø  -XX:+UseParallelGC: Enables the parallel garbage collector.

Ø  -XX:+UseConcMarkSweepGC: Enables the CMS garbage collector.

Ø  -XX:+UseG1GC: Enables the G1 garbage collector (default from Java 9).

Ø  -Xms: Sets the initial heap size.

Ø  -Xmx: Sets the maximum heap size.

Benefits of Garbage Collection in Java

Ø  Automatic Memory Management: Java developers do not need to manually manage memory allocation and deallocation.

Ø  Reduces Memory Leaks: Objects no longer in use are automatically removed.

Ø  Improved Application Stability: By reclaiming memory, GC ensures that an application doesn’t run out of memory, leading to more stable execution.

Downsides of Garbage Collection

Ø  Performance Impact: Garbage collection can introduce pauses (stop-the-world events) where the application is paused while memory is being reclaimed.

Ø  Overhead: In large applications, the overhead of garbage collection can become significant, affecting application performance.

 

 

How Garbage Collection Works in Java with a Class Example

Java automatically manages memory through Garbage Collection (GC), which is designed to find and remove objects that are no longer used by the program, freeing up heap space. Java uses the Mark and Sweep algorithm and several advanced techniques like Generational Garbage Collection to manage object lifecycle effectively.

Here's a detailed explanation of garbage collection in Java with a code example and an explanation of how the algorithm works.

Example Code: Garbage Collection in Action

java

class GarbageCollectionExample {

    private String objectName;

 

    public GarbageCollectionExample(String name) {

        this.objectName = name;

    }

 

    @Override

    protected void finalize() throws Throwable {

        // Called when the object is garbage collected

        System.out.println(objectName + " is garbage collected.");

    }

 

    public static void main(String[] args) {

        // Creating objects

        GarbageCollectionExample obj1 = new GarbageCollectionExample("Object 1");

        GarbageCollectionExample obj2 = new GarbageCollectionExample("Object 2");

        GarbageCollectionExample obj3 = new GarbageCollectionExample("Object 3");

 

        // Dereference objects to make them eligible for GC

        obj1 = null;

        obj2 = null;

 

        // Suggest garbage collection

        System.gc(); // Requesting garbage collection

 

        // More operations

        obj3 = null;

       

        // Another GC request

        Runtime.getRuntime().gc(); // Another way to request GC

    }

}

 

Key Parts of the Example:

  1. Dereferencing:

Ø  Objects obj1 and obj2 are set to null, making them eligible for garbage collection.

Ø  System.gc() and Runtime.getRuntime().gc() hint the JVM to start garbage collection, but it’s not guaranteed when it will happen.

  1. finalize() Method:

Ø  The finalize() method is called by the garbage collector just before an object is removed from memory. It’s a good place to release non-memory resources (like files, sockets), although it's rarely used in modern applications.

  1. Output:

Ø  When the garbage collector runs, it invokes finalize() on obj1 and obj2, and you’ll see output like:

Plain text

Object 1 is garbage collected.

Object 2 is garbage collected.

 

Mark and Sweep Algorithm for Garbage Collection

The Mark and Sweep algorithm is the foundation of how Java garbage collection works. Here's how it operates:

  1. Mark Phase:

Ø  The GC starts at the root objects (called GC Roots) and traverses all reachable objects, marking them as "alive."

Ø  GC Roots include:

ü  Active threads

ü  Local variables in stack frames

ü  Static fields

ü  JNI references

Ø  Any object that can be reached from a GC Root is considered "in use" and is marked for retention.

  1. Sweep Phase:

Ø  After the mark phase, the GC sweeps through the heap and collects any objects that were not marked as reachable. These unmarked objects are considered garbage and are cleared from memory.

  1. Compaction (optional):

Ø  Some garbage collectors (like the G1 GC) may compact memory after the sweep phase to reduce fragmentation by moving surviving objects together in memory.

Diagram: Mark and Sweep Process

Diff

Heap Memory

+----------------+------------------------+

|    Objects     |                                |

|                       |                                |

|   Reachable  |    Unreachable     |

|   Objects      |     Objects              |

+----------------+-------------------------+

     ^                             

     |                             

  Mark phase: GC traverses the heap, marks reachable objects.

    

+---------------------------+

| Sweep Phase:           |

| Collects the               |

| unreachable objects|

| Clears memory         |

+---------------------------+

 

Generational Garbage Collection

Java's garbage collectors use a generational approach to optimize the performance of garbage collection. The heap is divided into:

  1. Young Generation:

Ø  Most newly created objects are located here. It is further divided into:

ü  Eden Space: Where new objects are created.

ü  Survivor Spaces (S0 and S1): Objects that survive one garbage collection cycle are moved here.

Ø  Minor GC: A garbage collection that happens only in the young generation, quickly freeing space for new objects.

  1. Old Generation:

Ø  Objects that have survived multiple GC cycles are moved here. They are considered long-lived objects.

Ø  Major GC / Full GC: A garbage collection event that involves both the young and old generations. It's more expensive in terms of time.

 

 

Monitor of JVM memory usages

To monitor the JVM's memory usage and garbage collection activities using the jstat command, here’s a step-by-step guide based on your setup:

Steps:

  1. Start Your Application: You have already started the Java application with the following command:

Bash

java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar Test.jar

 

Ø  Flags used:

ü  -Xmx120m: Maximum heap size is 120 MB.

ü  -Xms30m: Initial heap size is 30 MB.

ü  -Xmn10m: Young generation size is 10 MB.

ü  -XX:PermSize=20m: Initial permanent generation (PermGen) size is 20 MB.

ü  -XX:MaxPermSize=20m: Maximum PermGen size is 20 MB.

ü  -XX:+UseSerialGC: Use Serial Garbage Collector.

  1. Find the Process ID: To monitor the Java process, first, you need to find its process ID (PID) by running:

bash

ps -eaf | grep Test.jar

 

From the output:

bash

501 9582  11579   0  9:48PM ttys000    0:21.66 /usr/bin/java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseG1GC -jar Test.jar

 

The PID of your application is 9582.

  1. Run jstat to Monitor GC: Now, use the jstat command to monitor the garbage collection statistics. The following command provides GC statistics every second (1000 milliseconds):

bash

jstat -gc 9582 1000

 

This will print garbage collection statistics at intervals of 1 second. The output will look like:

bash

S0C    S1C    S0U    S1U      EC       EU        OC        OU     PC      PU       YGC    YGCT   FGC    FGCT     GCT

8192.0 8192.0  0.0    0.0     32768.0  16384.0   49152.0   24576.0 20480.0  10240.0  5      0.03   2      0.10    0.13

8192.0 8192.0  0.0    0.0     32768.0  8192.0    49152.0   24576.0 20480.0  10240.0  6      0.04   3      0.12    0.16

 

Column Explanations:

Ø  S0C and S1C: Current size of Survivor 0 and Survivor 1 spaces (in KB).

Ø  S0U and S1U: Current usage of Survivor 0 and Survivor 1 spaces (in KB).

Ø  EC: Current size of the Eden space (in KB).

Ø  EU: Current usage of the Eden space (in KB).

Ø  OC: Current size of the Old generation (in KB).

Ø  OU: Current usage of the Old generation (in KB).

Ø  PC: Current size of the PermGen (in KB).

Ø  PU: Current usage of the PermGen (in KB).

Ø  YGC: Number of young generation GC events (Minor GCs).

Ø  YGCT: Time spent in young generation GC (Minor GCs), in seconds.

Ø  FGC: Number of full GC events.

Ø  FGCT: Time spent in full GC, in seconds.

Ø  GCT: Total time spent in GC (Minor + Full), in seconds.

  1. Stop Monitoring: When you're done monitoring, press Ctrl + C to stop the jstat output.

By using this method, you can continuously monitor how the JVM performs garbage collection and see how memory is being allocated and cleaned up, particularly in the Young Generation and Old Generation.

Explanation of the Command:

Ø  jstat -gc: This option reports the garbage collection statistics.

Ø  9582: The process ID of your Java application.

Ø  1000: The interval at which to report the statistics, in milliseconds (1 second in this case).

 

The memory usage at the time of the error

java

package com.kartik.error;

 

import java.lang.management.ManagementFactory;

import java.lang.management.MemoryMXBean;

import java.lang.management.MemoryUsage;

 

/**

 *

 * @author Kartik Chandra Mandal

 * How to handle run time exception in Java file

 */

public class RunTimeMemoryException {

    // Constant to convert bytes to megabytes

    private static final int MEGABYTE = (1024 * 1024);

 

    // Method that simulates an out of memory error

    public static void runOutOfMemoryError() throws Exception {

        // MemoryMXBean allows you to monitor the memory usage

        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();

        try {

            // Attempt to allocate a large amount of memory

            long[] data = new long[1000000000];

        } catch (Exception e) {

            // Handle any general exceptions

            throw new Exception("Exception occurred: " + e.getMessage());

        } catch (OutOfMemoryError e) {

            // Catch OutOfMemoryError specifically and provide heap memory details

            MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();

            long maxMemory = heapUsage.getMax() / MEGABYTE;

            long usedMemory = heapUsage.getUsed() / MEGABYTE;

            System.out.println("Memory Usage: " + usedMemory + " MB / " + maxMemory + " MB");

 

            // Throw a new exception to notify that the error was caught

            throw new Exception("Out of memory error by Kartik: " + e.getMessage());

        }

    }

 

    // Main method to run the example

    public static void main(String[] args) {

        try {

            // Attempt to run the memory-consuming method

            runOutOfMemoryError();

        } catch (Exception e) {

            // Print the exception message and stack trace

            System.out.println(e.getMessage());

            e.printStackTrace();

        }

    }

}

 

Breakdown of the Code:

  1. Memory Usage Monitoring:

Ø  The MemoryMXBean is used to access the JVM's memory management interface, which can retrieve memory statistics like heap usage.

Ø  The MemoryUsage class provides details about the heap's memory state (used, max, etc.).

  1. Exception Handling:

Ø  First, we handle any general exceptions with a catch (Exception e) block.

Ø  Then, we handle OutOfMemoryError separately, since it's not a subclass of Exception. In this case, we retrieve the current heap memory usage and rethrow it as a more general Exception with a custom message.

  1. Simulating Out of Memory:
    The code attempts to allocate a large array (long[] data = new long[1000000000];). This is likely to trigger an OutOfMemoryError, particularly if your JVM is running with a limited heap size.

Running and Monitoring the Program:

  1. Command to Start the Program: You can use the following JVM options to set the heap size and simulate an out-of-memory error:

bash

java -Xmx20m -Xms20m -XX:+UseSerialGC -jar RunTimeMemoryException.jar

 

This command will set both the initial and maximum heap size to 20 MB, which should be small enough to trigger an OutOfMemoryError when trying to allocate the large array.

  1. Using jstat: To monitor the garbage collection and memory usage, you can use the jstat tool as follows:

bash

jstat -gc <pid> 1000

 

Replace <pid> with the process ID of the running Java application. This will display the memory and GC statistics every second.

Sample Output:

Upon running the program, when the OutOfMemoryError is caught, the console will print:

bash

Memory Usage: 18 MB / 20 MB

Out of memory error by Kartik: Java heap space

java.lang.Exception: Out of memory error by Kartik: Java heap space

              at com.kartik.error.RunTimeMemoryException.runOutOfMemoryError(RunTimeMemoryException.java:24)

              at com.kartik.error.RunTimeMemoryException.main(RunTimeMemoryException.java:38)

 

 

By choosing the right garbage collector and tuning JVM parameters, developers can optimize performance based on the application's specific needs. 




Fig 1
Fig 1
JVM heap memory allocation
JVM heap memory allocation


Fig 2
Fig 2








Simulating Custom Heap Memory Management in JavaScript

Post a Comment

1 Comments

Kartik Chandra Mandal
amit singh rana said…
nice topic and nice explanation