Heap in JVM


  • Arrays are objects and are store in heapmemory
  • Heap stores the actual objects. 
  • It is created when the JVM starts up.
  • Heap size can be fixed or dynamic (using min and max memory)
  • We can increase the heapsize if required using JVM arguments
  • When you use a new keyword, the JVM creates an instance for the object in a heap. 
  • While the reference of that object stores in the stack. 
  • There exists only one heap for each running JVM process. When heap becomes full, the garbage is collected.

Example :

StringBuilder sb= new StringBuilder();  
  • The above statement creates an object of the StringBuilder class.
  • The object allocates to the heap, and the reference sb allocates to stack. 
  • Heap is divided into the following parts:
    • Young generation – this is where all new objects are allocated and aged. A minor Garbage collection occurs when this fills up
    • Old generation – this is where long surviving objects are stored. When objects are stored in the Young Generation, a threshold for the object’s age is set and when that threshold is reached, the object is moved to the old generation
    • Permanent generation(Non Heap) – this consists of JVM metadata for the runtime classes and application methods
    • Survivor space
    • Code Cache
Java Heap
enter image description here

Young Generation

  • It is the part of the heap. It is reserved for allocation of objects. 
  • When it becomes full, the minor GC collects the garbage from Eden to one of the survivor spaces.
  • Objects that are available for garbage in one of the survivor spaces are cleared, and remaining objects move to the other survivor space. Hence, there is always one empty survivor space. 
  • All objects that live long in the young space are transfers to old space.
  • Eden: All objects are first created here. It is bigger than the two survivor spaces. It consumes 76% space of the young generation. When Eden becomes full, a minor GC is triggered.
  • Survivor Spaces: It is a pool of objects that have survived the garbage collection of the Eden space. There are two survivor spaces called survivor from (S0) and survivor to (S1). It avoids memory fragmentation. The important point about the survivor is one of the two survivors is always empty.
  • The process of copying the live objects between survivor spaces is repeated several times until some objects are considered to have matured and old enough. 
  • Such objects can thus move to old space instead of move into other survivor space.
  • To determine whether the object is ready to move into old space, GC counts the total number of collections an object survived.

Old Generation

  • It contains objects that are lives long. This process is called an old collection.
  • Long-lived objects survived after many rounds of minor GC. 
  • When the old space is about to reach its limit, major resources of old memory are cleared. 
  • An old generation garbage collector is called a major GC

Permanent Generation (PermGen)(Non Heap)

  • JVM generates it at runtime. It contains the application metadata required by JVM.
  • Metadata includes the classes and methods used in the application. It also includes the Java SE library classes and methods.
  • Metaspace replaced it in Java 8.
  • It means java.lang.OutOfMemoryError does not occur in Java 8.
  • Two new flag introduced in metaspace they are: -XXMetasapceSize and ?XXMaxMetaspaceSize. The main motive of metaspace is that, as long as the classloader is alive, the metadata remains alive in the metaspace.
  • The main difference between PermGen and metaspace is: PermGen is a part of heap while the metaspace is a part of native memory.
Java Heap 2

Code Cache

Memory Management in Java: Java Virtual Machine (JVM) Memory Model
  • Code Cache: It is a memory area separate from the heap. It is used for compilation and storage of native code.
  • It is a fixed size space. If it became full, the JVM would not compile any additional code. To avoid this, you can tune the code cache with the following size options:
  • InitialCodeCacheSize: Its default size (bytes) is 160K.
  • ReservedCacheSize: Its default maximum size is 48M.
  • CodeCacheExpansionSize: Its default size is 32K or 64K.

JVM uses a Use Code Cache Flushing option to control the flushing of the code cache area. Its default value is false. Just-in-time (JIT) compiler is the biggest user of the code cache area.

The JVM offers a UseCodeCacheFlushing option to control the flushing of the code cache area. Its default value is false. When we enable it, it frees the occupied area when the following conditions are met:

  • the code cache is full; this area is flushed if its size exceeds a certain threshold
  • the certain interval is passed since the last cleanup
  • the precompiled code isn’t hot enough. For each compiled method the JVM keeps track of a special hotness counter. If the value of this counter is less than a computed threshold, the JVM frees this piece of precompiled code

Code Cache Usage Tracking

  • In order to monitor the code cache usage, we need to track the size of the memory currently in use.
  • To get information on code cache usage, we can specify the –XX:+PrintCodeCache JVM option. After running our application, we’ll see a similar output:

Let’s see what each of these values mean:

  • size in the output shows the maximum size of the memory, which is identical to ReservedCodeCacheSize
  • used is the actual size of the memory that currently is in use
  • max_used is the maximum size that has been in use
  • free is the remaining memory which is not occupied yet

The PrintCodeCache option is very useful, as we can:

  • see when the flushing happens
  • determine if we reached a critical memory usage point

Segmented Code Cache

As of Java 9, the JVM divides the code cache into three distinct segments each of which contains a particular type of compiled code. To be more specific, there are three segments:

  • The non-method segment contains JVM internal related code such as the bytecode interpreter. By default, this segment is around 5 MB. Also, it’s possible to configure the segment size via the -XX:NonNMethodCodeHeapSize tuning flag
  • The profiled-code segment contains lightly optimized code with potentially short lifetimes. Even though the segment size is around 122 MB by default, we can change it via the -XX:ProfiledCodeHeapSize tuning flag
  • The non-profiled segment contains fully optimized code with potentially long lifetimes. Similarly, it’s around 122 MB by default. This value is, of course, configurable via the -XX:NonProfiledCodeHeapSize tuning flag

This new structure treats various types of complied code differently, which leads to better overall performance.

For example, separating short-lived compiled code from long-lived code improves the method sweeper performance — mainly because it needs to scan a smaller region of memory.

OutOfMemory Example :

package com.memeory;

public class MemoryLeaksDemo {
	public static void main(String[] args) {
		// Get current size of heap in bytes
		long heapSize = Runtime.getRuntime().totalMemory(); 

		// Get maximum size of heap in bytes. The heap cannot grow beyond this size.// Any attempt will result in an OutOfMemoryException.
		long heapMaxSize = Runtime.getRuntime().maxMemory();

		 // Get amount of free memory within the heap in bytes. This size will increase // after garbage collection and decrease as new objects are created.
		long heapFreeSize = Runtime.getRuntime().freeMemory(); 
		System.out.println("Current HeapSize in bytes : "+heapSize/1024/1024+" MB");
		System.out.println("Max HeapSize in bytes : "+heapMaxSize/1024/1024+" MB");
		System.out.println("Free HeapSize in bytes : "+heapFreeSize/1024/1024+" MB");
		int[] arr = new int[999999999]; // allocating memory to array

Note : Since array is created using new keyword the memory is allocated in Heap and its reference is stored in stack.

Reference Type

  • There are four types of references: StrongWeakSoft, and Phantom reference.
  • The difference among the types of references is that the objects on the heap they refer to are eligible for garbage collecting under the different criteria.

Strong reference: It is very simple as we use it in our daily programming. Any object which has Strong reference attached to it is not eligible for garbage collection. We can create a strong reference by using the following statement:

StringBuilder sb= new StringBuilder();  

Weak Reference: It does not survive after the next garbage collection process. If we are not sure when the data will be requested again. In this condition, we can create a weak reference to it. In case, if the garbage collector processes, it destroys the object. When we again try to retrieve that object, we get a null value. It is defined in java.lang.ref.WeakReference class. We can create a weak reference by using the following statement:

WeakReference<StringBuilder> reference = new WeakReference<>(new StringBuilder());  

Soft Reference: It is collected when the application is running low on memory. The garbage collector does not collect the softly reachable objects. All soft referenced object s are collected before it throws an OutOfMemoryError. We can create a soft reference by using the following statement:

SoftReference<StringBuilder> reference = new SoftReference<>(new StringBuilder());  

Phantom Reference: It is available in java.lang.ref package. It is defined in java.lang.ref.PhantomReference class. The object which has only phantom reference pointing them can be collected whenever garbage collector wants to collect. We can create a phantom reference by using the following statement:

PhantomReference<StringBuilder> reference = new PhantomReference<>(new StringBuilder());

Reference :

Leave a Comment