Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

JVM Memory Allocation and Garbage Collection Strategies

Tech 1

Java’s automatic memory management relies on well-defined allocation and reclamation strategies within the heap. These mechanisms ensure efficient object lifecycle handling without manual intervention.

1. New Objects Allocated in Eden

By default, newly created objects are placed in the Eden space of the young generation. When Eden lacks sufficient contiguous space, a Minor GC is triggered to reclaim unused objects.

public class EdenAllocation {
    private static final int MB = 1024 * 1024;

    public static void allocate() {
        byte[] obj1 = new byte[2 * MB];
        byte[] obj2 = new byte[2 * MB];
        byte[] obj3 = new byte[2 * MB];
        byte[] obj4 = new byte[4 * MB]; // Triggers Minor GC if Eden is full
    }

    public static void main(String[] args) {
        allocate();
    }
}

VM arguments: -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -verbose:gc

2. Large Objects Bypass Young Generation

Objects exceeding a certain size threshold are allocated directly in the old generation to avoid expensive copying between Eden and Survivor spaces during Minor GCs. This behavior is controlled by -XX:PretenureSizeThreshold.

public class LargeObjectAllocation {
    private static final int MB = 1024 * 1024;

    public static void allocateLarge() {
        byte[] bigObj = new byte[4 * MB]; // Goes straight to old gen if > threshold
    }

    public static void main(String[] args) {
        allocateLarge();
    }
}

VM arguments include: -XX:PretenureSizeThreshold=3145728 (3MB)

3. Aging and Promotion to Old Generation

Each time an object survives a Minor GC, its age counter increments. Once it reaches the maximum tenuring threshold (default: 15), it is promoted to the old generation. The threshold can be adjusted via -XX:MaxTenuringThreshold.

public class ObjectAging {
    private static final int MB = 1024 * 1024;

    public static void testPromotion() {
        byte[] small = new byte[MB / 4];
        byte[] large1 = new byte[4 * MB];
        byte[] large2 = new byte[4 * MB];
        large2 = null;
        large2 = new byte[4 * MB]; // May trigger promotion based on age
    }

    public static void main(String[] args) {
        testPromotion();
    }
}

Use -XX:+PrintTenuringDistribution to observe age distribution.

4. Dynamic Age-Based Promotion

HotSpot may promote objects earlier than the configured MaxTenuringThreshold if the total size of objectss of a given age exceeds half the Survivor space. This optimization reduces Survivor pressure.

public class DynamicPromotion {
    private static final int MB = 1024 * 1024;

    public static void testDynamicAge() {
        byte[] a = new byte[MB / 4];
        byte[] b = new byte[MB / 4]; // Combined, they exceed half of Survivor
        byte[] c = new byte[4 * MB];
        byte[] d = new byte[4 * MB];
        d = null;
        d = new byte[4 * MB];
    }

    public static void main(String[] args) {
        testDynamicAge();
    }
}

Run with -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution.

5. Space Allocation Guarantee

Before a Minor GC, the JVM checks whether the old generation has enough free space to accommoadte all live objects from the young generation. If not, it evaluates historical promotion data:

  • If -XX:-HandlePromotionFailure is set (default in newer JDKs), a Full GC is triggered when old gen space is insufficient.
  • In older versions, if HandlePromotionFailure was enabled, the JVM compared available space against average promotion size before deciding.

Since JDK 6u24, the rule simplifies: Minor GC proceeds only if old gen has more free space than the total young gen size; otherwise, Full GC occurs.

public class SpaceGuarantee {
    private static final int MB = 1024 * 1024;

    public static void testGuarantee() {
        byte[] o1 = new byte[2 * MB];
        byte[] o2 = new byte[2 * MB];
        byte[] o3 = new byte[2 * MB];
        o1 = null;
        byte[] o4 = new byte[2 * MB];
        byte[] o5 = new byte[2 * MB];
        byte[] o6 = new byte[2 * MB];
        o4 = o5 = o6 = null;
        byte[] o7 = new byte[2 * MB]; // May trigger Full GC due to space guarantee
    }

    public static void main(String[] args) {
        testGuarantee();
    }
}

VM argument: -XX:-HandlePromotionFailure forces conservative behavior.

Tags: JVM

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.