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.
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.
The following are the essential principles in Java Memory Management:
1) JVM Memory Structure
2) Garbage Collector's Operation
Let's look at them.
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
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 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.
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:
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.
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
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.
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.
Garbage Collector Types
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.
- 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:
- 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:
- 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 for obtaining the best GC performance.
Two types of GCs are generally concurrent:
fast throughput combined with a quick application pause time. Enabled by selecting the following option:
Concurrent Mark Sweep
The time the application is paused is kept to a minimum. It is activated by specifying the next option:
This GC type has been deprecated since JDK 9.
Frequently Asked Questions
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.
What Is the Difference Between StringBuilder and StringBuffer?
StringBuffer differs from StringBuilder in that it can be used safely by several threads. Use StringBuilder instead if you need to manipulate a string on a single thread.
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. Do upvote our blog to help other ninjas grow.
We wish you Good Luck! Keep coding and keep reading Ninja!!