Back to Memory Management & GC
Q13Question 13 of 21

What was PermGen and how does Metaspace fix it?

Key Concepts
  • PermGen: fixed size in heap, caused OOM: PermGen space
  • Metaspace: native memory, grows dynamically, no fixed limit by default
  • Configurable: -XX:MaxMetaspaceSize
  • ClassLoader leaks can still exhaust Metaspace
  • Understanding this concept is essential for Java interviews at senior level

Definition

PermGen was a fixed-size heap region for class metadata. It caused OOM when full. Metaspace (Java 8+) uses native memory that grows dynamically.

- PermGen: fixed size in heap, caused OOM: PermGen space\n- Metaspace: native memory, grows dynamically, no fixed limit by default\n- Configurable: -XX:MaxMetaspaceSize\n- ClassLoader leaks can still exhaust Metaspace

Understanding the Concepts

What is What was PermGen and how does Metaspace fix it?

What was PermGen and how does Metaspace fix it is an important concept in Java that every banking application developer should understand. In the context of National Bank of India's transaction processing system, Rajesh uses this concept regularly when building reliable financial services.

- PermGen: fixed size in heap, caused OOM: PermGen space\n- Metaspace: native memory, grows dynamically, no fixed limit by default\n- Configurable: -XX:MaxMetaspaceSize\n- ClassLoader leaks can still exhaust Metaspace

JAVA
package com.bank.core;

import java.math.BigDecimal;

public class ConceptDemo {
    private String accountId = "SAV2001";
    private BigDecimal balance = new BigDecimal("50000.00");

    public static void main(String[] args) {
        ConceptDemo demo = new ConceptDemo();
        System.out.println("Account: " + demo.accountId);
        System.out.println("Balance: " + demo.balance);
    }
}
TEXT
Account: SAV2001
Balance: 50000.00

Why does What was PermGen and how does Metaspace fix it matter?

Understanding What was PermGen and how does Metaspace fix it is critical for building production-grade banking applications. Without this knowledge, developers may write code that behaves unexpectedly under load or fails in edge cases.

At National Bank of India, Pankaj emphasizes that every developer on the team must understand this concept because it directly affects the reliability and performance of the transaction processing pipeline.

  • It affects how the JVM manages memory and resources.
  • It influences the behavior of concurrent banking transactions.
  • It determines how objects are created, stored, and cleaned up.
  • It impacts application performance under high transaction volumes.
JAVA
package com.bank.service;

import java.math.BigDecimal;

public class TransferService {
    public boolean transfer(String fromAccount, String toAccount, BigDecimal amount) {
        // This demonstrates why understanding the concept matters
        BigDecimal fromBalance = getBalance(fromAccount);
        if (fromBalance.compareTo(amount) >= 0) {
            debit(fromAccount, amount);
            credit(toAccount, amount);
            System.out.println("Transferred " + amount + " from " + fromAccount + " to " + toAccount);
            return true;
        }
        System.out.println("Insufficient balance in " + fromAccount);
        return false;
    }

    private BigDecimal getBalance(String accountId) {
        return new BigDecimal("100000.00");
    }
    private void debit(String accountId, BigDecimal amount) { /* debit logic */ }
    private void credit(String accountId, BigDecimal amount) { /* credit logic */ }
}

How does What was PermGen and how does Metaspace fix it work internally?

When the JVM processes this concept, it follows a specific internal mechanism. The JVM specification defines the behavior precisely, which ensures consistent results across different JVM implementations.

JAVA
package com.bank.internal;

import java.math.BigDecimal;

public class InternalBehaviorDemo {
    public static void main(String[] args) {
        // Step 1: Object creation on the heap
        BigDecimal balance = new BigDecimal("75000.00");

        // Step 2: JVM processes the operation
        BigDecimal interest = balance.multiply(new BigDecimal("0.045"));

        // Step 3: Result is a new immutable object
        System.out.println("Interest: " + interest);
        System.out.println("Original unchanged: " + balance);
    }
}
TEXT
Interest: 3375.000
Original unchanged: 75000.00

How is this used in a banking application?

In National Bank of India's core banking system, Rajesh applies this concept in several places:

  • Account processing: When creating and managing customer accounts.
  • Transaction logging: When recording financial transactions for audit.
  • Interest calculation: When computing daily interest on savings accounts.
  • Statement generation: When building monthly statements for customers like Priya.
JAVA
package com.bank.model;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class Transaction {
    private final String transactionId;
    private final String fromAccount;
    private final String toAccount;
    private final BigDecimal amount;
    private final LocalDateTime timestamp;

    public Transaction(String txnId, String from, String to, BigDecimal amount) {
        this.transactionId = txnId;
        this.fromAccount = from;
        this.toAccount = to;
        this.amount = amount;
        this.timestamp = LocalDateTime.now();
    }

    @Override
    public String toString() {
        return "TXN[" + transactionId + "] " + fromAccount + " -> " + toAccount + " : " + amount;
    }

    public static void main(String[] args) {
        Transaction txn = new Transaction("TXN-001", "SAV2001", "CUR3001", new BigDecimal("5000.00"));
        System.out.println(txn);
    }
}
TEXT
TXN[TXN-001] SAV2001 -> CUR3001 : 5000.00

What are common mistakes?

A common mistake is not understanding the full implications of this concept in a banking production environment.

Wrong approach:

JAVA
package com.bank.service;

public class WrongApproach {
    public void processAccount() {
        // WRONG: using double for money
        double balance = 10000.50;
        double fee = 0.1;
        double result = balance - fee;
        System.out.println(result);  // 10000.4 (precision lost!)
    }
}

Correct approach:

JAVA
package com.bank.service;

import java.math.BigDecimal;

public class CorrectApproach {
    public void processAccount() {
        // CORRECT: using BigDecimal for money
        BigDecimal balance = new BigDecimal("10000.50");
        BigDecimal fee = new BigDecimal("0.10");
        BigDecimal result = balance.subtract(fee);
        System.out.println(result);  // 10000.40 (exact!)
    }
}

What should a senior engineer know?

A senior engineer should understand the production implications:

  • Performance profiling: Use JFR (Java Flight Recorder) and JMC (Java Mission Control) to measure the impact in production.
  • Thread safety: Consider how this concept interacts with concurrent access in a multi-threaded banking service.
  • JVM tuning: Adjust JVM parameters based on the workload characteristics of the banking application.
  • Monitoring: Set up JMX metrics and alerts in production to detect issues early.
JAVA
package com.bank.monitoring;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;

public class JvmInfoDemo {
    public static void main(String[] args) {
        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
        System.out.println("JVM: " + runtime.getVmName());
        System.out.println("Uptime: " + runtime.getUptime() + " ms");
        System.out.println("Input args: " + runtime.getInputArguments());
    }
}

What are the edge cases?

JAVA
package com.bank.edge;

import java.math.BigDecimal;

public class EdgeCaseDemo {
    public static void main(String[] args) {
        // Edge case 1: null handling
        String accountId = null;
        System.out.println(accountId == null);  // true

        // Edge case 2: BigDecimal equality
        BigDecimal a = new BigDecimal("10.0");
        BigDecimal b = new BigDecimal("10.00");
        System.out.println(a.equals(b));       // false (different scale)
        System.out.println(a.compareTo(b) == 0); // true (same value)

        // Edge case 3: Integer caching
        Integer x = 127;
        Integer y = 127;
        System.out.println(x == y);  // true (cached)
        Integer p = 128;
        Integer q = 128;
        System.out.println(p == q);  // false (not cached)
    }
}
TEXT
true
false
true
true
false

What are common interview follow-up questions?

  • How does this concept interact with garbage collection?
  • What tools would you use to debug issues related to this concept?
  • How does this behave differently in Java 8 vs Java 17+?
  • What are the thread safety implications?
  • How would you optimize this for a high-throughput banking system?

Key Takeaway

PermGen was a fixed-size heap region for class metadata. It caused OOM when full. Metaspace (Java 8+) uses native memory that grows dynamically.\n\n

Remember one sentence: What was PermGen, why did it cause OutOfMemoryError: PermGen space (fixed size, hot-deploy class leaks), and how does Metaspace (Java 8+, native memory, classloader-scoped collection) fix it is fundamental knowledge for Java interviews and production banking work.

---

Share
Use ← → arrow keys to navigate