In Java, it is important to keep the memory utilisation in such a way that responsive and efficient applications can be developed. Garbage collection in Java is one of the major functions that is responsible for automatically deallocating the memory by removing any unreferenced objects. Without garbage collection, Java programs would face performance issues and possible crashes due to memory shortages.
This blog will help you understand the garbage collection process in Java, its phases and the different types of garbage collectors. In addition, we will explain the most optimal practices for garbage collection management whilst providing you with guidance on the ideal garbage collector configuration for your application and the advantages that come with it.
What is a Garbage Collection?
Garbage collection is an automatic memory management system employed in Java in which the available memory is freed by systematically searching for unused objects. In Java, once an object is instantiated, it blocks a distinct amount of machine memory to hold that object. As the program runs, many objects become unreachable or unnecessary, meaning they can no longer be accessed by any part of the application. Garbage collection helps to reclaim this memory, making it available for future use and ensuring that the application runs efficiently without manually managing memory allocation.
The Java Virtual Machine (JVM) performs garbage collection automatically, eliminating the need for developers to manually free memory, as is required in languages like C or C++. This is a process that entails finding objects that are no longer referenced by any part of the program and no longer utilised for their intended function and eliminating them. In doing so, the possibility of memory matters associated with memory is mitigated, allowing developers to concentrate on writing codes more than managing memory.
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure
How Does Garbage Collection in Java Work?
Garbage collection in Java operates by functioning to search and remove any objects or variables that are no longer in the use of the program. This procedure is made up of several stages such as object referencing, absence of object, and deallocation of associated memory.
The Role of the Java Virtual Machine (JVM)
The Java Virtual Machine (JVM) can be defined as the space that is used to execute Java code. It manages when memory is taken by specific objects and when it is released. Every time a Java application is executed, the JVM will reserve some spaces for the object in a memory space referred to as the heap. The heap consists of dynamic memory used to create new objects and exposes memory allocated to the Java virtual machines’ garbage collector which can release this memory as the objects are no longer active.
Understanding Object References
In Java, Java objects are placed in the heap memory and are only accessed via references. As long as an object is reachable through one or more references, it remains in memory and is not eligible for garbage collection. When all of the reference pointers that point to an object are removed, that object becomes eligible to be reclaimed, i.e. garbage collected. There are three other common ways to perform this action in Java.
1. Setting the Reference to null
The simplest way to dereference an object is by setting its reference to null. This method poses no risk to the object since the last reference variable correlating it has already been removed, thus readily making it available to the garbage collector.
public class DereferenceExample1 {
public static void main(String[] args) {
// Creating an object of StringBuilder
StringBuilder builder = new StringBuilder("Hello, World!");
// Dereference by setting the reference to null
builder = null; // Now, the object is eligible for garbage collection
}
}
In this example, the StringBuilder object is created and then dereferenced by assigning null to its reference variable builder. This makes the object eligible for garbage collection since no active references are pointing to it.
2. Reassigning the Reference to Another Object
Another way to dereference an object is by reassigning the reference to a different object. This breaks the link between the reference variable and the original object, making the original object unreachable.
public class DereferenceExample2 {
public static void main(String[] args) {
// Creating an object of StringBuilder
StringBuilder builder1 = new StringBuilder("First Object");
// Creating another object of StringBuilder
StringBuilder builder2 = new StringBuilder("Second Object");
// Reassigning the reference
builder1 = builder2; // Now, the "First Object" is eligible for garbage collection
}
}
Here, builder1 initially points to the “First Object”. When builder1 is reassigned to builder2, the reference to the “First Object” is lost, making it eligible for garbage collection.
3. Exiting the Scope of the Reference
When a reference goes out of scope, it is automatically dereferenced. This commonly occurs with local variables inside methods. Once the method completes execution, any local objects created inside the method that are not referenced elsewhere become eligible for garbage collection.
public class DereferenceExample3 {
public static void main(String[] args) {
createObject();
// At this point, the object created in createObject() is no longer reachable
}
public static void createObject() {
// Creating an object of StringBuilder
StringBuilder builder = new StringBuilder("Scoped Object");
// The object will be eligible for garbage collection when this method ends
}
}
In this example, the StringBuilder object builder is created inside the createObject method. Once the method completes, the reference goes out of scope, and the object is eligible for garbage collection since it is no longer reachable.
Phases of Garbage Collection
The hierarchy of garbage collection is achieved within three stages of the process namely: the marking stage, the deletion stage and finally the compacting stage.
Marking Phase: The initial thing that the garbage collector looks for is all objects that are currently active. It starts from a set of known objects, known as Garbage Collection Roots (GC Roots), and traverses all objects reachable from these roots. During this action, any object which could not be reached will have been slotted for deletion.
Deletion Phase: Once the unreachable objects have been identified, the garbage collector takes care of memory reclamation up to the last object that is accessible in the process. Depending on the garbage collector used, the deletion can be done in different ways, such as sweeping through memory and clearing the marked objects.
Compacting Phase: In some cases, the garbage collection will cause the rest of the objects left in the memory space to be packed into one unit. Such an operation involves gathering the reachable objects and then changing all their references to where the objects are located. This helps in the effective use of memory space, and improving performance.
Garbage Collection Algorithms
Java provides the user with various garbage collection methods to facilitate memory management. Following were the basic and most common algorithms:
Serial Garbage Collector: This is the simplest garbage collector that uses a single thread to perform all garbage collection work.
Parallel Garbage Collector (Throughput Collector): This collector collects garbage in parallel on many threads to reduce the pause time while performing garbage collection and increase throughput. This collector adapts to multi-threaded processes where demands on performance are highly intensified.
CMS (Concurrent Mark-Sweep) Garbage Collector: This garbage collector allows collection work as much as possible in parallel with the application itself to decrease pauses of application execution. It helps in use cases which need low Latency performance at execution.
G1 (Garbage-First) Garbage Collector: G1 is meant for applications that run on multiple threads and are of a large size. It splits the heap into regions and targets the inclusion of the most collected regions in the first place, thus making a compromise between throughput and pause time.
How Java Collects Garbage – Example with Code
Here is an example demonstrating the concept of garbage collection in Java using the System.gc() method, which suggests the JVM to perform garbage collection.
public class GCExample {
public static void main(String[] args) {
// Create an object of ExampleClass
ExampleClass example = new ExampleClass();
// The object is still reachable here
System.out.println("Example object is created.");
// Set the reference to null to make the object eligible for garbage collection
example = null;
// Suggest garbage collection
System.gc();
// Pause to let garbage collection happen
try {
Thread.sleep(1000); // Sleep for 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Garbage collection has been suggested.");
}
// A simple class to demonstrate garbage collection
static class ExampleClass {
// Override the finalise method to see when garbage collection happens
@Override
protected void finalize() throws Throwable {
System.out.println("ExampleClass object is being garbage collected.");
}
}
}
In this example:
An object of ExampleClass is created, which is initially reachable.
The reference to the object is set to null, making it eligible for garbage collection.
The System.gc() call suggests the JVM to perform garbage collection. Note that this is a suggestion and the JVM is not required to act immediately.
The finalize method is overridden in ExampleClass to print a message when the object is being collected, allowing us to see when garbage collection occurs.
Finalization and Object Destruction
Java provides a mechanism called finalisation that allows objects to perform cleanup before they are collected. The finalise method is called by the garbage collector on an object before memory is reclaimed. However, finalisation is generally discouraged in modern Java development due to its unpredictability and performance overhead.
Triggers for Garbage Collection
Garbage collection in Java is typically triggered automatically based on the JVM’s memory needs. The JVM monitors the usage of heap memory and triggers garbage collection when memory usage reaches a certain threshold. The frequency and type of garbage collection can vary depending on the JVM configuration and the selected garbage collector.
How to Select the Right Garbage Collector
Choosing the right garbage collector (GC) in Java is essential for optimising your application’s performance. The choice depends on your application’s needs, memory patterns, and environment. Here’s a straightforward guide to help you decide:
Low Latency Requirements: If your application needs to minimise pause times (e.g., real-time systems or interactive applications):
Consider G1 Garbage Collector: Balances throughput and low pauses by collecting regions with the most garbage first.
Choose Z Garbage Collector (ZGC): Offers very low pause times and handles large heaps efficiently.
High Throughput Needs: If your application focuses on maximising processing speed and can handle longer pauses:
Parallel Garbage Collector (Throughput GC): Uses multiple threads for garbage collection, reducing overall time spent on memory cleanup. Ideal for batch processing or big data tasks.
Simple Environments or Limited Resources: For small applications or single-core systems:
Serial Garbage Collector: Single-threaded and has low overhead. Best suited for simpler applications where latency is less of a concern.
To choose the right GC, follow these steps:
Profile Your Application:
Use tools like VisualVM or Java Flight Recorder to understand memory usage and garbage collection behaviour.
Identify how often objects are created and destroyed and how this impacts performance.
Test Different Collectors:
Use JVM options like:
-XX:+UseG1GC for G1.
-XX:+UseZGC for ZGC.
-XX:+UseSerialGC for Serial GC.
Measure application performance under different conditions to find the most suitable collector.
Consider Your Environment:
Single-Core CPUs: Prefer Serial GC.
Multi-Core CPUs: Parallel GC or G1 GC can leverage multiple threads.
Large Heaps: Use G1 GC or ZGC for better performance.
By profiling, testing, and understanding your environment, you can select the garbage collector that best matches your application’s performance needs.
Advantages of Garbage Collection
Garbage collection (GC) in Java is also referred to as automatic memory recycling which assists in dealing with memory problems, providing easier ways to develop applications. With this feature, developers are able to devote themselves to the writing of codes rather than being involved in memory management.
Auto-Configured Memory Management: Confers space by removing unreachable objects, and therefore the risk of memory loss is eliminated.
Better Stability of an Application: Possible memory problems including crashes or slow performance are minimised.
Less difficult to develop the application: The developers do not have to manually manage memory allocation and deallocation and as such, developing applications in Java is less complex.
Garbage Collection Best Practices
If you want garbage collection to work better and your application to be more optimised, please keep in mind these best practices. These practices help to achieve an acceptable level of memory and performance of applications.
Pick the Suitable Garbage Collector: Choose the proper GC depending on the characteristics of the application; Low latency, high throughput or some other specification.
Reduce the Creation of Objects: In most cases, there is no need to create many surplus objects which increases the amount of garbage collection performed.
Use the Right Data Structures: Use primitive data structures that are light on memory, for example, ArrayList instead of LinkedList.
Avoid too Much GC: Periodically get a report of the application with VisualVM or JConsole to get the memory usage behaviour of the application and optimise it.
Conclusion
Garbage collection in the Java programming language is a crucial tool that helps in the management of memory resources in the appropriate way by eliminating the objects that the program does not require any more. Gaining this understanding involves understanding different phases of garbage collectors and their functionalities, and processes for identifying the right one. This can greatly enhance the performance and stability of your application.
If you follow optimally Good practices like selecting the appropriate garbage collector, reducing wasteful object instantiation, and watchful management of GC, you will be able to effectively make use of available memory. Tuning the garbage collection process effectively helps in achieving consistent performance in applications and developers will be able to spend little time on memory management and more on writing relevant code.
FAQs
What is garbage collection in Java?
Garbage collection is a memory management technique in the Java programming language that automatically reclaims memory by destroying objects that the program can no longer use or access.
Why is garbage collection important?
Garbage collection is very crucial to the operation because it avoids unwanted excess memory space usage, enhances the overall system efficiency, and minimises the complexity of program development.
Which garbage collector should I use?
You will choose whatever seems befitting the circumstance. For low latency, one would opt for instance G1 or ZGC while for maximum throughput parallel GC should be used.
Can I force garbage collection in Java?
You can request the JVM to perform garbage collection via System.gc() but it is not guaranteed that it will perform a garbage collection.
What are GC Roots in Java?
GC Roots signifies the objects from where any garbage collection starts tracing the reach of the objects.
Does garbage collection impact performance?
Yes, in case garbage collection is not executed properly, it may induce interruptions or lag in an application.
How can I monitor garbage collection?
Use tools like VisualVM, JConsole, or Java Flight Recorder to monitor GC activity and optimise performance.
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.