Memory Management in Java : pt-2

Stack, Heap, Context, Code and Garbage Collection

Hi guys, today I'll be talking about memory management in java, and the various areas (virtual) in memory that are created by the JVM. So let's begin !

Physical Level

First of all, you should understand that Stack and Heap do not have a physical representation - it is a memory abstraction, so there is no physical difference between them, they are both in RAM.

These abstractions are created by the OS and are helping us to develop good software and not to think about where the variables and methods are going in RAM and keep tracking it there. So in modern High-level programming languages like Java, the memory management is taken care of by the language internals itself - JVM in the case of java.

JVM is designed to be robust so that even if there is a crash in the operating system, the program that is running on the JVM is not affected. Memory management means managing every piece of memory (RAM) in a computer system. JVM monitors allocating and releasing memory when needed.

Memory Allocation in Java

Memory Allocation in Java is the process in which the virtual memory sections are set aside in a program for storing the variables and instances of objects, fields(variables), classes, and, methods.

However, the memory isn’t allocated to an object at declaration but only a reference is created. For the memory allocation of the object, the new keyword is used, so the object is always allocated memory on the heap. ( I will talk about this in another post ).

The Java Memory Allocation is divided into the following sections :

  1. Heap
  2. Stack
  3. Code
  4. Context (Static/MetaSpace/PermGen)

This division of memory is required for its effective management.

memory.avif

  1. Code - The code area contains your bytecode.
  2. Stack - The Stack area of memory contains methods, local variables, and reference variables.
  3. Heap - The Heap area contains Objects (may also contain reference variables).
  4. Context - The context area contains Static data/methods.

Points to Remember -

  1. The instance variable is declared inside a class but not inside a method.

  2. Local variables are declared inside a method including method parameters.

Code

I will not say much about this area because as the name suggests, the Code area will store the bytecode (compiled code) of the program. Every instruction and every method of the program starts at a particular address.

Context

The context area contains Static data/methods. Will talk more about this area in a future post where I explain the storage of static fields and methods in a Java program :)

Stack

Stack in java is a section of memory that contains methods, local variables, and reference variables. Stack memory is always referenced in Last-In-First-Out order. Local variables are created in the stack.

The Stock Memory allocation in java is used for static memory and thread execution. The values contained in this memory are temporary and limited to specific methods as they keep getting referenced in Last-In-First-Out fashion.

As soon as the memory is called and a new block gets created in the stack memory, the stack memory then holds primitive values and references until the method lasts. After its ending, the block is flushed and is available for a new process to take place. In general, the overall size of the stack memory is insignificant to that of the heap memory.

Characteristics of Stack Memory -

  1. The stack memory can grow or contract as any new methods get called and returned accordingly. It is a stack afterall !

  2. Any variable in the stack can run as long as the scope of the method exists.

  3. It does auto-allocation and deallocation as and when a method undergoes execution.

This means after the execution of a function is finished, the frame of that function is flushed out of the stack memory space, and when a new function is called, a new frame for that function is created on top of the caller function's frame in the stack, and the control of the program is transferred to the new function, in other words the new function will be in focus now.

I will explain the function memory map in a future post. :)

  1. In the case of full memory, the java.lang.StackOverFlowError sets off.

  2. It is faster in access when compared to the heap memory.

  3. Stack memory area is smaller as compared to Heap memory area.

  4. This memory is threadsafe, as each thread operates in its own stack.

Methods used in the stack memory allocation in Java -

  1. Object push(Object element): Here, an item gets pushed to the top of the stack.

  2. Object pop(): Any element located at the top of the stack gets flushed and returned. In case of a stack being vacant as the pop() gets invoked, the exception – EmptyStackException occurs.

  3. Object peek(): Here, the top element gets returned but doesn’t undergo flushing.

  4. Boolean empty(): If the loop doesn’t have any top value in its stack, the function returns true, or false.

  5. search(Object element): This is used to understand if an object is present in the stack. In case the value is found, the function returns the location of the element from the top of the stack, otherwise returns -1.

Heap

Heap space is used for the dynamic memory allocation of Java objects and JRE classes at runtime. New objects are always created in heap space, and the references to these objects are stored in stack memory.

Instance variables are also created in the heap.

Mainly used by java runtime, Java Heap Space comes into play every time an object is created and allocated in it. The discrete function, like Garbage Collection, keeps flushing the memory used by the previous objects that hold no reference. For an object created in the Heap Space can have free access across the application.

We can break this memory model down into smaller parts, called generations, which are:

  1. Young Generation(nursery)

This is where all new objects are allocated and aged. Whenever this memory gets filled, the garbage collection is performed. This is called Minor Garbage Collection.

  1. Old or Tenured Generation

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.

All the long-lived objects which have survived many rounds of minor garbage collection are stored in this area. Whenever this memory gets filled, the garbage collection is performed. This is called Major Garbage Collection.

  1. Permanent Generation(PermGen)

This is where the static members of the class were stored before Java 8. PremGen was deprecated after Java 8. This consists of JVM metadata for the runtime classes and application methods. Metadata is data that is used to describe the data. Here, garbage collection also happens like any other part of the memory.

String pool was also part of this memory before Java 7. Method Area is a part of space in the PermGen and it is used to store the class structure and the code for methods and constructors.

The biggest disadvantage of PermGen is that it contains a limited size which leads to an OutOfMemoryError.

Due to this, JVM had to change the size of this memory by frequently performing Garbage collection which is a costly operation. Java also allows to manually change the size of the PermGen memory. However, the PermGen space cannot be made to auto increase. So, it is difficult to tune it. And also, the garbage collector is not efficient enough to clean the memory.

Due to the above problems, PermGen has been completely removed in Java 8. In the place of PermGen, a new feature called MetaSpace has been introduced. MetaSpace grows automatically by default. Here, the garbage collection is automatically triggered when the class metadata usage reaches its maximum metaspace size.

MetaSpace

MetaSpace or Context area or Static Area is the place where all the static members are stored as of the latest Java version (>= Java 8). It is part of the native memory provided by the OS to JVM. It helps in efficient memory management in Java.

Heap and MetaSpace are auto-growing memory areas whereas PremGen was a fixed memory allocated area in RAM. It led to inefficient memory allocation in Java.

Characteristics of Heap Memory -

  1. Accessible from the complicated memory management technique, including the Young Generation, Old or Tenured Generation, etc.

  2. In heap memory, when it gets full, it throws java.lang.OutOfMemoryError.

  3. The access to this memory is comparatively slower than that of the stack memory.

  4. It doesn’t undergo automatic deallocation and requires Garbage Collector to remove foreign objects for the memory to work in its optimal stage.

  5. Unlike stack, a heap isn't threadsafe and needs to be guarded by properly synchronizing the code.

Garbage Collection in Java

The Java Virtual Machine (JVM) uses reference counting to track the number of Java objects. Before any object can be collected, the number of references to this object must reach zero.

The user program can explicitly delete objects by calling finalize() method. Finalize is a static method in the Object class which is called by Garbage Collector (GC). Finalize method will release all the resources of the object before Garbage Collector will take care of this object.

Garbage Collector is the process of cleaning unwanted objects. The process of Garbage Collector will be triggered when the Java run-time system detects that the Java heap is almost full. Every object has a bitmap in JVM. The bitmap is set for each object to track whether it's been used or not. When the bitmap is turned to 0, GC will take care of this object.