For working professionals
For fresh graduates
More
6. JDK in Java
7. C++ Vs Java
16. Java If-else
18. Loops in Java
20. For Loop in Java
46. Packages in Java
53. Java Collection
56. Generics In Java
57. Java Interfaces
60. Streams in Java
63. Thread in Java
67. Deadlock in Java
74. Applet in Java
75. Java Swing
76. Java Frameworks
78. JUnit Testing
81. Jar file in Java
82. Java Clean Code
86. Java 8 features
87. String in Java
93. HashMap in Java
98. Enum in Java
101. Hashcode in Java
105. Linked List in Java
109. Array Length in Java
111. Split in java
112. Map In Java
115. HashSet in Java
118. DateFormat in Java
121. Java List Size
122. Java APIs
128. Identifiers in Java
130. Set in Java
132. Try Catch in Java
133. Bubble Sort in Java
135. Queue in Java
142. Jagged Array in Java
144. Java String Format
145. Replace in Java
146. charAt() in Java
147. CompareTo in Java
151. parseInt in Java
153. Abstraction in Java
154. String Input in Java
156. instanceof in Java
157. Math Floor in Java
158. Selection Sort Java
159. int to char in Java
164. Deque in Java
172. Trim in Java
173. RxJava
174. Recursion in Java
175. HashSet Java
177. Square Root in Java
190. Javafx
Memory management is a key part of any programming language—and Java makes it easier with garbage collection. In Java, garbage collection is the process of automatically freeing memory by deleting unused objects. This built-in feature helps developers avoid memory leaks, improve performance, and write cleaner code.
Garbage collection is handled by the Java Virtual Machine (JVM). It makes memory management more efficient and less error-prone compared to languages that require manual cleanup.
In this blog, you'll learn what garbage collection is, how it works in Java programming, why it's important, and which algorithms the JVM uses. Whether you're just starting with Java or want to improve application performance, understanding this process is essential.
Software engineering courses can make these concepts easier to grasp with real-time practice and guidance.
Garbage collection in Java refers to the automatic process of identifying and removing objects that are no longer reachable or used by an application. This memory management mechanism is integrated into the Java Runtime Environment (JRE) and operates in the background without explicit programmer intervention.
Memory management is a critical aspect of any programming language. Before Java, languages like C and C++ required manual memory allocation and deallocation, which often led to several issues:
Java's garbage collection eliminates these problems by automating the memory management process. It allows developers to focus on application logic rather than memory concerns.
Take your skills to the next level with these highly rated courses.
To understand garbage collection in Java, you must first grasp these fundamental concepts:
The heap is the runtime data area from which memory for all class instances and arrays is allocated. It is created when the JVM starts and may increase or decrease in size during application execution.
Memory Area | Description | Garbage Collected? |
Heap | Where objects reside | Yes |
Stack | Where method frames and local variables reside | No |
Metaspace (PermGen in older versions) | Where class metadata resides | Partially |
Native Memory | Memory used for JVM code itself | No |
Objects in Java go through a predictable lifecycle:
Garbage collection in Java determines which objects to collect based on reachability. An object is considered reachable if:
Objects that are not reachable through any of these paths are eligible for garbage collection.
Must read: Stack and Heap Memory in Java: Key Differences Explained
Garbage collection in Java follows a process known as "mark and sweep." This two-phase approach forms the foundation of Java's memory management:
Some advanced garbage collectors add a third phase:
Also read: Comprehensive Guide to Exception Handling in Java
To determine reachability, the garbage collector starts from "GC roots" and traverses all object references. GC roots include:
Any object that cannot be reached from one of these roots is considered garbage.
public class GarbageCollectionExample {
public static void main(String[] args) {
// Object creation
Object obj1 = new Object(); // obj1 is reachable
Object obj2 = new Object(); // obj2 is reachable
// obj1 is now unreachable, eligible for garbage collection
obj1 = null;
// Request garbage collection (though not guaranteed to run immediately)
System.gc();
System.out.println("Garbage collection requested");
}
}
In this example, after setting obj1 to null, the original Object instance becomes unreachable and is eligible for garbage collection. The System.gc() call suggests (but does not guarantee) that the JVM perform garbage collection.
In modern JVMs, memory allocation is highly optimized. Most allocations occur in thread-local allocation buffers (TLABs), which minimize thread contention and improve performance. When an object is created:
Several garbage collection algorithms have been implemented in Java, each with distinct characteristics suited to different application requirements.
The Mark-Sweep-Compact algorithm extends the basic mark-sweep approach by adding a compaction phase:
This algorithm effectively addresses memory fragmentation but requires more processing time due to the additional compaction phase.
The copying algorithm divides the heap into two equal spaces: "from-space" and "to-space":
This approach eliminates fragmentation and provides fast allocation but requires twice the memory space.
// Example demonstrating memory behavior with copying collection
public class CopyingGCDemo {
public static void main(String[] args) {
// Create a large array that will be copied during GC
int[] largeArray = new int[1000000]; // Approximately 4MB
// Fill the array with some values
for (int i = 0; i < largeArray.length; i++) {
largeArray[i] = i;
}
// Force a garbage collection
System.gc();
// Check memory usage after GC
Runtime rt = Runtime.getRuntime();
long usedMemory = rt.totalMemory() - rt.freeMemory();
System.out.println("Memory used after GC: " + (usedMemory / 1024 / 1024) + " MB");
}
}
The original Mark-Sweep algorithm:
This algorithm is simple but suffers from memory fragmentation over time.
Also read: Thread Lifecycle in Java
Generational garbage collection in Java is based on the empirical observation known as the "generational hypothesis," which states that most objects die young. This insight led to the development of a garbage collection strategy that divides the heap into generations:
The Young Generation is where new objects are allocated. It is further divided into:
The Young Generation is designed for rapid collection using a copying collector.
Objects that survive multiple collections in the Young Generation are eventually promoted to the Old Generation. This area is typically larger and collected less frequently using algorithms optimized for longer-lived objects.
public class GenerationalGCExample {
public static void main(String[] args) {
// Fill up the Eden space
List<byte[]> allocations = new ArrayList<>();
// Allocate many objects, forcing some to be promoted
for (int i = 0; i < 100; i++) {
// Allocate arrays of increasing size
allocations.add(new byte[i * 10000]);
// Force minor GCs occasionally
if (i % 20 == 0) {
System.gc();
System.out.println("Minor GC triggered, iteration: " + i);
}
}
// Objects still in the list have survived multiple GCs
// and have likely been promoted to the Old Generation
System.out.println("Final allocation count: " + allocations.size());
}
}
The JVM offers several garbage collector implementations, each designed for different use cases and performance requirements.
The Serial GC is the simplest implementation, using a single thread for garbage collection operations. It's suitable for single-threaded applications or those with small heaps.
Key characteristics:
The Parallel GC (also known as Throughput Collector) uses multiple threads for garbage collection operations, reducing collection time.
Key characteristics:
The CMS Collector is designed to minimize pause times by performing most garbage collection work concurrently with the application threads.
Key characteristics:
The G1 GC is designed for servers with large amounts of memory. It divides the heap into regions and prioritizes collection in regions with the most garbage.
Key characteristics:
The ZGC is designed for applications requiring low latency and can handle heaps from a few gigabytes to multi-terabyte sizes.
Key characteristics:
Shenandoah is a low-pause-time garbage collector that reduces GC pause times by performing more garbage collection work concurrently with the running Java program.
Key characteristics:
Let's examine a more complex example that demonstrates garbage collection behavior:
import java.util.ArrayList;
import java.util.List;
public class AdvancedGCExample {
// A class with a finalizer to demonstrate finalization
static class DataObject {
private byte[] data = new byte[100000]; // 100KB
@Override
protected void finalize() throws Throwable {
System.out.println("DataObject being finalized");
super.finalize();
}
}
public static void main(String[] args) throws InterruptedException {
// Configure VM arguments to see GC details:
// -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xmx256m
List<DataObject> objects = new ArrayList<>();
// Phase 1: Create objects that stay in memory
System.out.println("Creating permanent objects...");
for (int i = 0; i < 10; i++) {
objects.add(new DataObject());
}
// Phase 2: Create temporary objects that should be collected
System.out.println("Creating temporary objects...");
for (int i = 0; i < 10000; i++) {
DataObject temp = new DataObject();
// temp becomes eligible for GC at the end of each loop iteration
}
// Request garbage collection
System.out.println("Requesting garbage collection...");
System.gc();
// Give finalizers a chance to run
Thread.sleep(1000);
// Phase 3: Create more objects to potentially trigger promotion
System.out.println("Creating more objects...");
for (int i = 0; i < 10000; i++) {
if (i % 1000 == 0) {
objects.add(new DataObject()); // Some objects are retained
} else {
DataObject temp = new DataObject(); // Most are temporary
}
}
// Final GC to clean up
System.out.println("Final garbage collection...");
System.gc();
System.out.println("Retained objects: " + objects.size());
}
}
Output:
Creating permanent objects...
Creating temporary objects...
Requesting garbage collection...
DataObject being finalized
DataObject being finalized
...
Creating more objects...
Final garbage collection...
DataObject being finalized
DataObject being finalized
...
Retained objects: 20
This example demonstrates:
Parameter | Description | Example Value |
-Xms | Initial heap size | -Xms1g |
-Xmx | Maximum heap size | -Xmx4g |
-XX:NewRatio | Ratio of Old/Young generation sizes | -XX:NewRatio=2 |
-XX:SurvivorRatio | Ratio of Eden/Survivor space sizes | -XX:SurvivorRatio=8 |
-XX:MaxGCPauseMillis | Target maximum GC pause time | -XX:MaxGCPauseMillis=200 |
-XX:GCTimeRatio | Ratio of GC time to application time | -XX:GCTimeRatio=19 |
-Xlog:gc | GC logging | -Xlog:gc*:file=gc.log |
Symptoms:
Causes:
Solutions:
Symptoms:
Causes:
Solutions:
Symptoms:
Causes:
Solutions:
Example code to generate a heap dump on OutOfMemoryError:
// Run with: java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump.hprof MemoryLeakExample
public class MemoryLeakExample {
private static final List<byte[]> leakyList = new ArrayList<>();
public static void main(String[] args) {
try {
while (true) {
// Keep adding 1MB arrays to the list
leakyList.add(new byte[1024 * 1024]);
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
System.err.println("OutOfMemoryError occurred: " + e.getMessage());
// A heap dump has been created at the specified path
// Analyze it with tools like VisualVM or MAT
}
}
}
Check out: Multithreading in Java
Several tools are available for monitoring garbage collection:
Enabling GC logging provides valuable insights:
# Modern JVM (Java 9+)
-Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=10M
# Older JVM versions
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log
Sample GC log entry (G1 GC):
[2023-05-01T15:30:45.123+0000][gc,start ] GC(36) Pause Young (Normal) (G1 Evacuation Pause)
[2023-05-01T15:30:45.123+0000][gc,task ] GC(36) Using 8 workers of 8 for evacuation
[2023-05-01T15:30:45.128+0000][gc,phases ] GC(36) Pre Evacuate Collection Set: 0.1ms
[2023-05-01T15:30:45.128+0000][gc,phases ] GC(36) Evacuate Collection Set: 4.2ms
[2023-05-01T15:30:45.128+0000][gc,phases ] GC(36) Post Evacuate Collection Set: 0.5ms
[2023-05-01T15:30:45.128+0000][gc,phases ] GC(36) Other: 0.3ms
[2023-05-01T15:30:45.129+0000][gc,heap ] GC(36) Eden regions: 25->0(25)
[2023-05-01T15:30:45.129+0000][gc,heap ] GC(36) Survivor regions: 4->4(4)
[2023-05-01T15:30:45.129+0000][gc,heap ] GC(36) Old regions: 16->18
[2023-05-01T15:30:45.129+0000][gc,heap ] GC(36) Humongous regions: 5->5
[2023-05-01T15:30:45.129+0000][gc,metaspace ] GC(36) Metaspace: 35868K->35868K(1081344K)
[2023-05-01T15:30:45.129+0000][gc ] GC(36) Pause Young (Normal) (G1 Evacuation Pause) 50M->27M(256M) 5.1ms
[2023-05-01T15:30:45.129+0000][gc,cpu ] GC(36) User=0.03s Sys=0.00s Real=0.01s
Key metrics to analyze:
Garbage collection in Java represents a fundamental advancement in programming language design, automating memory management and eliminating entire classes of errors common in manual memory management systems
While the concepts are straightforward, the implementation details and tuning options provide developers with powerful tools for optimizing application performance.
From the basic mark-sweep algorithm to sophisticated collectors like ZGC and Shenandoah, Java's garbage collection ecosystem continues to evolve to meet the demands of modern applications.
By understanding how garbage collection works internally, recognizing different collector algorithms, and applying proper optimization techniques, developers can harness the full potential of Java while maintaining optimal memory utilization and application responsiveness.
Garbage collection in Java occurs when the JVM determines that memory needs to be reclaimed. This typically happens when:
The exact timing is non-deterministic and depends on the JVM implementation and garbage collector being used.
You can request garbage collection using System.gc() or Runtime.getRuntime().gc(), but the JVM is not obligated to honor this request immediately or at all. It treats these calls as suggestions rather than commands. Relying on explicit garbage collection calls is generally discouraged as the JVM's automatic collection is usually more efficient.
To prevent an object from being garbage collected, maintain a strong reference to it from a reachable object. Common approaches include:
The finalize() method is an object method called by the garbage collector before reclaiming an object's memory. It's unpredictable, not guaranteed to run, and considered legacy.
The try-with-resources statement is a language feature for automatically closing resources that implement AutoCloseable. It's deterministic, immediate, and the recommended approach for resource management.
Weak references (java.lang.ref.WeakReference) don't prevent their referents from being garbage collected. If an object is only weakly reachable (no strong or soft references), it can be collected in the next GC cycle. This is useful for implementing caches and preventing memory leaks.
Several factors can contribute to high memory usage after garbage collection:
Choosing a garbage collector depends on your application's requirements:
Consider your hardware, application characteristics, and performance requirements when making this decision.
Garbage collection improves developer productivity by automating memory management but can introduce performance overheads:
Pros:
Cons:
Modern collectors balance these tradeoffs effectively for most applications.
Memory leaks can be detected through:
Large object heaps present challenges for garbage collection:
Modern collectors like G1 and ZGC are designed for large heaps:
Calling System.gc() explicitly is generally discouraged because:
Take the Free Quiz on Java
Answer quick questions and assess your Java knowledge
Author|900 articles published
Previous
Next
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918068792934
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.