JVM Heap Memory
What Is Heap Memory?
Heap memory is the space where objects dynamically created while a Java program runs (objects or instances created with the new operator) are stored.
Objects created here can be referenced by fields of other objects or by methods that exist on the stack. If the referencing variable disappears, the object is considered unnecessary and is deallocated by the Garbage Collector.
Role of the Heap Memory Area
Heap memory is the space where objects dynamically created while a Java program runs (objects or instances created with the new operator) are stored.
Objects created here can be referenced by fields of other objects or by methods that exist on the stack. If the referencing variable disappears, the object is considered unnecessary and is deallocated by the Garbage Collector.
The heap area has several functions, so it is divided into multiple parts. It is managed by separating the space where objects are first created from the space where objects are moved after not being used for a certain time so that garbage collection can be performed.
Java 7 HotSpot JVM

Java 8 HotSpot JVM

Young Generation
This is the space in heap memory where newly created objects are first placed.
The Young Generation is divided as follows.
- Eden
- This is the memory area allocated immediately after a Java object is created. In other words, newly created objects made with the
newoperator are placed here.
- This is the memory area allocated immediately after a Java object is created. In other words, newly created objects made with the
- Survivor1, Survivor2
- When each area becomes full, surviving objects move to the empty Survivor area.
- At this time, objects without references are collected by Minor GC.
Old Generation
Objects that survive garbage collection to the end in the Young Generation come to the Old Generation. In other words, this is the area where old data is stored.
Major GC occurs here, and it happens less frequently than Minor GC.
Permanent Generation
Permanent Generation is the area where class or method code is stored. PermGen belongs to the Heap area.
PermGen, short for Permanent Generation, is a special heap space separate from the main Java heap that the JVM uses to track metadata for loaded classes.
Permanent Generation stores data that is more or less guaranteed not to change, such as information about loaded classes.
It has a limited default size. (32-bit JVM: 64MB, 64-bit JVM: 82MB)
JVM Argument
-XX:PermSize=N --> Set the default PermGen size.
-XX:MaxPermSize=N --> Set the maximum PermGen size.
Metaspace Generation
With the release of Java 8, there was a change in the JVM area. Among the JVM memory areas, the Permanent Generation memory area disappeared and the Metaspace area was introduced. Metaspace replaces the Perm area from before Java 8 and is the area where class and method metadata is stored.
- Metaspace is the space where metadata for classes loaded so far by Java’s Classloader is stored.
- The important point is that it is located in native memory, not the Heap area.
- It does not have a limited default size. Therefore, it continues to grow as needed.
- Starting with Java 8, JVM options related to PermGen are ignored.
JVM Argument
-XX:MetaspaceSize=N
-XX:MaxMetaspaceSize=N
- MetaspaceSize: Sets the default Metaspace size.
- This setting is used to change the amount of native memory used by the JVM.
- Use this option if you are confident that the system will use more memory than the default provided by the system.
- MaxMetaspaceSize: Sets the maximum Metaspace size.
- This setting is used to change the maximum amount of memory for metaspace.
- Use it when you want to tune the memory area while running an application on a server or when you want to prevent a memory leak from consuming the entire system’s native memory.
- If native memory is full but the application still requests more memory,
java.lang.OutOfMemoryError: Metadata spaceoccurs. - If no setting is specified, no limit is applied.
Permanent and Metaspace
In Java 8, PermGen was renamed to Metaspace, although there are some differences. The important point is that Metaspace has no default maximum size. By contrast, PermGen in Java 7 and earlier has a default maximum size of 64MB on 32-bit JVMs and 82MB on 64-bit versions. Of course, this is not the same as the initial size. Java 7 and earlier start with roughly 12-21MB of initial PermGen space.
The comparison of default limited sizes for Permanent and Metaspace is as follows.
| JVM | Default maximum PermGen size (MB) | Default maximum Metaspace size |
|---|---|---|
| 32-bit client JVM | 64 | unlimited |
| 32-bit server JVM | 64 | unlimited |
| 64-bit JVM | 82 | unlimited |
Before Java 7, interned strings were stored in PermGen. This caused the following well-known serious error.
java.lang.OutOfMemoryError: PermGen space
Whenever the size of PermGen/Metaspace must be adjusted, the JVM adjusts it like the standard heap. Adjusting the size of this space requires a full GC, which is always expensive. This is commonly observed during startup when many classes are loaded, especially when an application depends on many external libraries. If many Full GCs occur during startup, this is often the reason. In such cases, increasing the initial size can improve startup performance.
The advantages and disadvantages of the change from PermGen to Metaspace are as follows.
Advantages
- Because the PermGen area was removed, the memory available to the heap area increased.
- Several complex pieces of code that existed to remove the PermGen area were removed, and the time spent scanning the PermGen area decreased, improving GC performance.
Disadvantages
- Although PermGen space can no longer be exhausted (because PermGen no longer exists), excessive native memory can be consumed, increasing the overall process size.
- The problem is that if an application loads many classes or strings, it can actually bring down not only the application but also the entire server. This is because native memory is limited only by the operating system. In other words, it can consume all memory on the server.
Managing Memory Through Java Code
Let’s analyze Java code and look at how memory is managed here.
class Person {
int id;
String name;
public Person(int id, String name) {
this.id = id;
this.name = name;
}
}
public class PersonBuilder {
private static Person buildPerson(int id, String name) {
return new Person(id, name);
}
public static void main(String[] args) {
int id = 23;
String name = "John";
Person person = null;
person = buildPerson(id, name);
}
}
- When the
main()method is entered, space is created in stack memory to store the method’s primitives and references.- Stack memory directly stores the primitive value of the integer
id. - The reference variable
personof type Person is also created in stack memory and points to the actual object in the heap.
- Stack memory directly stores the primitive value of the integer
- The call from
main()to the parameterized constructorPerson(int, String)allocates additional memory on top of the previous stack. This stores:- The
thisobject reference of the called object in stack memory - The primitive value
idin stack memory - The reference variable for the string argument name, which points to the actual string in the string pool in heap memory
- The
- The main method additionally calls the static method
buildPerson(), and an additional allocation occurs in stack memory on top of the previous method for this method. This stores variables again in the manner described above. - However, heap memory stores all instance variables for the newly created object
personof typePerson.
This allocation is shown in the diagram below.
Source: https://www.baeldung.com/java-stack-heap