Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
Memory is a valuable resource in every computer language, and it is also limited in nature. As a result, memory must be well-managed and free of errors.
Memory management in Java is allocating and releasing memory to Java objects stored in the Stack and Heap sections. Garbage Collector is an automatic memory deallocation system in Java.
Here we will learn about the Java Virtual Machine(JVM) and the Memory management model of JVM, Garbage Collector.
What is memory management in Java?
Memory management in Java is a constant challenge and a skill that must be learned if applications are properly optimised and scalable. It is allocating new objects and appropriately deleting those no longer needed.
Java offers automatic memory management, with a lovely and silent garbage collector that cleans up unneeded objects and frees up memory in the background.
As a result, as a Java programmer, you won't have to worry about issues like object destruction because they're no longer needed. However, even if this process is automated in Java, nothing is guaranteed. You may have objects that are not eligible for garbage collection because you don't understand how the garbage collector and Java memory are constructed, even if you no longer utilise them.
Knowing how memory works in Java is vital because it allows you to write high-performance code.
Principles in Java Memory Management
The following are the essential principles in Java Memory Management:
1) JVM Memory Structure
2) Garbage Collector's Operation
JVM and its Memory Structure
The Java Virtual Machine (JVM) allows a computer to execute a Java application. There are three concepts of JVM:
Specification: where the JVM's operation is specified
Implementations: Java Runtime Environment(JRE)
Instantiation: call the constructor of a class to generate an instance or object of that class's type.
The Java Virtual Machine loads, validates, and executes code, manages memory(including allocating memory from the Operating System (OS), managing Java allocation, and garbage object cleanup), and provides the runtime environment.
JVM Memory Structure
Heap Memory
It is a shared runtime data area that keeps track of the actual object. It is created when the virtual machine is first started.
All class instances and arrays are given this amount of memory. The heap might be fixed or dynamic in size, depending on the system's setup.
For a JVM process that is executing, there is only one heap.
Let's have a look at what happens in the following line of code:
StringBuilder string = new StringBuilder();
The new keyword ensures enough free space on the heap, constructing a StringBuilder object in memory, and referring to it via the "string" reference which goes onto the Stack.
Non-Heap Memory
Non-Heap Memory is the memory that exists outside of the heap in the Java Virtual Machine. It's constructed when the JVM starts up and contains per-class structures, including the runtime constant pool, field and method data, method and function code, and interned Strings.
Other
It stores JVM code, internal JVM structures, loaded profiler agent code, and data.
When Code Cache reaches a certain usage level, it is flushed (the Garbage Collector does not relocate objects).
Runtime Data Area of JVM
In a heap, the JVM builds several run-time data areas. During the program's execution, certain areas are used. When the JVM exits, these memory areas are destroyed, whereas the data areas are deleted when the thread leaves.
Here is the diagram of Java Memory Area Parts:
Method Area
It is the memory that all Threads, such as Heap, share. It is formed during the initialization of the Java Virtual Machine. It contains the code, which is compiled code, methods, data, and fields. Method Area also includes a runtime constant pool.
JVM allocates memory for it by default, which can be raised if necessary. Constant Pool at Runtime is a per-class representation of the constant Table.
It contains all literals defined at compilation time and references that will be resolved at runtime.
Heap
The actual item is stored in this section of memory. The variables from the stack are used to refer to them.
Garbage Collection uses heap memory to liberate memory utilised by objects with no reference. Any object created in a heap has global access and can be accessed from anywhere in the application.
The following sections comprise the heap:
The Young generation part
The Survivor space part
The Old generation part
The Permanent generation part
The Code Cache part
Stack
Each thread produced by the application generates a stack. A thread links it. There is a separate stack for each thread. The stack stores all local variables and function calls. Its life is dependent on the Thread's life; if the Thread is alive, it will be live as well, and vice versa.
Variables in the stack also have particular visibility, often known as scope. Only the active scope's items are used. For example, suppose there are no global scope variables (fields) and only local variables. The compiler can only access items from the stack within the method's body when it executes the method's body. Other local variables are out of scope, so it can't access them.
Program Counter(PC) Registers
It's also linked through the thread that runs through it. It's essentially the address of the currently executed instruction. Because each thread has a set of methods depending on the PC Register, each thread has a set of methods that will be performed. Each JVM instruction has a value, and for native methods, it is undefined. It's typically used to keep track of instructions.
Native Method Stack
Methods created in languages other than Java are known as native methods. JVM implementations are unable to load native methods and are unable to use traditional stacks. It's also connected to each thread. In a nutshell, it's similar to stack. However, it's only utilised for native methods.
What is Java Garbage Collector?
Java's Garbage Collector (GC) is like an automatic cleanup system in Java that manages memory. Imagine it as a housekeeping service that keeps your program's memory clean and organized.
When you write a Java program, you create objects that take up memory space. Over time, some of these objects are no longer needed or used by your program. The Garbage Collector's job is to find these unused objects and remove them, freeing up memory for new objects.
Garbage Collection
Garbage collection is clearing space in the heap so that new objects can be assigned. Automatic garbage collection is one of Java's best features. Garbage Collector is a background application that searches all of the items in the memory for things that aren't referenced by any program component. These unreferenced items are removed, freeing up space to allocate to other things.
Three phases are involved in one of the most basic garbage collecting methods:
Marking: This is the initial phase in the garbage collection process when the garbage collector determines which objects are in use and which are not.
Deletion in the Normal Mode: The garbage collector collects unused items and reclaims the space for other things.
Deletion with compacting: After eliminating unnecessary items, all remaining objects can be moved together for better performance. This will improve the performance of memory allocation to newer objects.
Types of Garbage Collection
The JVM has three different garbage collectors, and the programmer can pick which one to use. Java selects the garbage collector type based on the underlying hardware by default.
1. Serial GC
A collector for a single thread. This is most common in small applications with less data utilisation. The following command-line argument can be used to enable it: -XX:+UseSerialGC
2. Parallel GC
Despite the names, the difference between Serial and Parallel GC is that Parallel GC performs garbage collection using several threads. The throughput collector is another name for this GC type. One can enable it by supplying the option explicitly: -XX:+UseParallelGC
3. Mostly concurrent garbage collection
As mentioned earlier in this article, the garbage collection process is quite expensive, and when it runs, all threads are paused. However, we have a mainly concurrent GC type, which means it runs in the background while the application is running. There is, however, a justification for it being "largely" concurrent. It does not run in complete parallel with the programme. The threads are halted for a certain amount of time. The pause is kept short to obtain the best GC performance.
Mark and Sweep Algorithm
It's the basic garbage collection algorithm with two phases:
Mark Phase: Starting from root objects, it traverses all object references and marks all "reachable" objects as alive
Sweep Phase: Scans the entire heap and removes unmarked objects (garbage)
During this process, the application completely stops (Stop-the-World pause), Simple but inefficient for large applications
Example process:
Object obj1 = new Object(); // Marked (reachable)
Object obj2 = new Object(); // Marked (reachable)
obj1 = null; // obj1's original object becomes unreachable
// During sweep phase, obj1's original object is removed
Concurrent Mark and Sweep
Designed to reduce pause times by doing most work concurrently with the application
Phases:
Initial Mark (STW): Quickly marks root objects
Concurrent Mark: Traces references while the application runs
Remark (STW): Catches changes during the concurrent mark
Concurrent Sweep: Removes garbage while the application runs
Better response time but uses more CPU resources
Can suffer from heap fragmentation
Parallel Mark and Sweep
Similar to basic Mark and Sweep but uses multiple threads
All GC threads work simultaneously during both the mark and sweep phases
Still causes Stop-the-World pauses but they're shorter
Beneficial for multi-core systems
Ideal for batch processing applications where throughput is more important than pause times
Better performance on large heaps
Default GC for server-class machines before Java 9
Frequently Asked Questions
Is Java good for memory management?
Yes, Java is effective for memory management due to its automatic garbage collection, which helps manage memory allocation and deallocation, reducing memory leaks.
Is there any Disadvantage of Garbage collectors?
Yes. The garbage collector impacts the application's performance whenever it runs. All other threads in the application must be paused for the garbage collector thread to complete its job correctly.
What is Generational Garbage Collection?
Generational garbage collection can be loosely characterised as the garbage collector's approach of dividing the heap into several generations. Each will hold objects based on their "age" on the heap.
When Does an Object Become Garbage Collection Available?
If an item is not reachable from any live threads or by any static references, it becomes eligible for garbage collection or GC. When all of an object's references are null, it's easy to see why it's eligible for garbage collection.
What Happens When There Isn't Enough Heap Space for New Objects to Be Stored?
If there isn't enough memory in Heap to create a new object, the Java Virtual Machine throws an OutOfMemoryError or java.lang.OutOfMemoryError heap space.
Conclusion
In this article, we have extensively discussed Important Principles of Java Memory Management, Java Virtual Machine, JVM Memory architecture, Runtime Data Areas of JVM like Method Area, Heap, Stack, PC registers, and Native Method Stack.
We also discussed Garbage Collection and Garbage collector types in JAVA.
We hope that this blog has helped you enhance your knowledge regarding Java Memory Management and if you would like to learn more, check out our article on Memory Management in Java.