Java Memory Architecture and Metaspace

Purpose

This article discusses the basic concept of Java memory management and the basics of GC along with heap and stack memory.

Garbage Collection

The Java program compiles and changes into byte code and runs on a JVM (Java Virtual Machine). Objects of a Java program get created on the dedicated heap memory for that program. Over time, more objects get created and some of the objects (un-referenced and de-scoped) are no longer needed by the program. Garbage collection is the process of Java that performs automatic memory management and frees up memory space by removing the un-referenced objects.

JVM incorporates different algorithms for garbage collection. The garbage collection algorithm checks for each referenced object in memory and the rest of the objects are considered to be garbage collected.

Importance of Memory Management

Java garbage collector doesn’t ensure that the heap memory will be completely free, and also, for a developer, it is not possible to force a garbage collector to run at a specific time. So it is helpful to know how memory management in Java works.

Understanding memory management helps with writing an optimized memory efficient code and helps to avoid any memory-related issues in the program, which can cause application slowness or OutOfMemoryError.

Stack Memory

Stack is a linear data structure and is a static memory allocation by Java to store heap object references and also stores Java primitive type values. Stack accesses the memory in a last in, first out (LIFO) order and stack is faster than heap memory.

Each thread creates its own stack in the memory, which in turn makes the stack memory thread safe.Thread1 and thread n

A method in Java only accesses the objects from the stack memory which are within the method body (within the method scope). When the method execution is complete, the corresponding block to this method gets cleared from the stack.

Stack: num=10, args=empty array

In the above program, we can see that when the control reaches to the main method, there will be an entry of the args in the stack. And then when the control is in the next line, a new entry is added to the stack.

When the control is out of the scope of the method, the reference gets deleted from the stack.

Reference is deleted from stack

In case the stack memory gets full, JVM throws a StackOverFlowError.

Heap Memory

Heap is used for dynamic memory allocation by JVM for Java objects at runtime. Any new object gets stored in heap and the reference(example variables) of the object is stored on the stack. You can see in the example below how the variables for the sample code are stored in the heap and stack.

int age = 5;
String name = "Sherine";
List<String> subjectLst = new ArrayList<String>();
subjectLst.add("English");
subjectLst.add("Science");
List<String> finalLst;
finalLst = subjectLst;

Below is the memory allocation in the heap for the above code snippet.

Memory allocation diagram

Heap memory can be broken down into smaller parts called generations, which are young, old/tenured, and permanent generations.

Young Generation

All new objects get assigned in this memory segment. The young generation consists of Eden and two Survivor spaces. When Eden fills up, the garbage collection happens on the young generation and that is called Minor GC. Referenced objects from the young generation are moved to Survivor space #1 during Minor GC and the age of the object gets incremented.

For example in the image below “Object 1” and “Object 2” will move to Survivor space #1 after the first Minor GC and they will have an assigned age. If the “Object 1” survives first Minor GC, then the age is zero. Now if the “Object 1” survives next Minor GC also, then it will be moved to Survivor space #2 and the age will be one.

Before Minor GC diagram

Image 1: Eden is full and before Minor GC

During the second Minor GC, objects (which have a reference) residing in Survivor space #1 will be moved to Survivor #2, and the age will be incremented (ie the age will become from zero to one as per the example). And all the un-referenced objects from full Young Generation space will be deleted.

After first Minor GC diagram

Image 2: After first Minor GC

Old Generation

The old generation is the place where the long-lived objects (most aged objects) are stored. Young generation objects have an upper limit or threshold for age. Once an object reaches that upper limit, then the object is moved to old or tenured generation.

Old generation in heart diagram

Permanent Gen

This part of heap memory is used to store metadata for runtime classes and methods. This part of the memory has been removed completely from JDK 8 onwards by Java and replaced by Metaspace. You can still set the --XX:PermSize and -XX:MaxPermSize configuration. But you will get a warning during runtime if you run the application on JDK 8 or a higher version.

Heap — Untill JDK 7

Metaspace

This was introduced from JDK 8 version and onwards, and it is a resizable memory area inside the heap. Metaspace holds the class metadata and it is not a contiguous memory location.

Whenever Metaspace reaches its maximum size allocated for the Metaspace, Java triggers automatic GC to free up Metaspace memory.

Metaspace can be set using -XX:MetaspaceSize=size and -XX:MaxMetaspaceSize=size parameters.

Heap — From JDK 8 and onwards

.

Leave a Comment