Understanding Java Garbage Collection: Algorithms, References, and Finalization
This article explains Java's garbage collection mechanisms, covering memory regions, the limitations of reference counting, the root search algorithm, various reference types, the two-phase marking process, and how the method area is reclaimed, illustrated with code examples and diagrams.
1. Overview of Java Garbage Collection
Java runtime memory is divided into several areas. The program counter, virtual machine stack, and native method stack are created and destroyed with each thread, and their stack frames allocate memory that is known when the class is loaded, so they do not require explicit garbage collection. The heap and method area, however, allocate memory dynamically at runtime, and the garbage collector focuses on reclaiming memory in these regions.
2. Reference Counting Algorithm
In interviews, one might suggest adding a reference counter to each object, incrementing it on each new reference and decrementing it when a reference is lost; an object with a count of zero would be considered unreachable. Although this algorithm is simple and efficient, Java does not use it because it cannot handle cyclic references.
Example of a cycle:
public class ReferenceCountingGC {
public Object instance = null;
private static final int _1MB = 1024 * 1024;
private byte[] bigSize = new byte[2 * _1MB];
public static void testGC() {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
System.gc();
}
}The JVM still collects the two objects, showing that Java does not rely on reference counting.
3. Root Search Algorithm
Java GC uses a "root search" algorithm. Starting from GC roots, it traverses the object graph; any object not reachable from a root forms an unreachable reference chain and is eligible for collection.
Typical GC roots in Java include:
References in the VM stack (local variable tables).
Static fields in the method area.
Constants in the method area.
JNI (native) references in the native method stack.
Objects that are unreachable from these roots, such as object5, object6, and object7 in the diagram, will be reclaimed.
4. Types of References
Java defines four reference strengths, from strongest to weakest:
Strong Reference : ordinary references (e.g., Object obj = new Object();) that prevent the object from being collected.
Soft Reference : used for memory‑sensitive caches; the object is reclaimed only when the JVM is about to throw an OutOfMemoryError.
Weak Reference : the object is reclaimed at the next GC cycle regardless of memory pressure.
Phantom (Virtual) Reference : does not affect object lifetime; it is used only to receive a notification after the object has been reclaimed.
5. Two‑Phase Marking During GC
When an object is found unreachable, the GC performs two marking steps. First, it marks the object and checks whether it overrides finalize(). If finalize() is needed, the object is placed in an internal F‑Queue and a low‑priority finalizer thread later invokes finalize(). The finalizer can resurrect the object by creating a new strong reference.
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive() {
System.out.println("yes, i am still alive");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method executed!");
SAVE_HOOK = this; // resurrect
}
public static void main(String[] args) throws Throwable {
SAVE_HOOK = new FinalizeEscapeGC();
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no, i am dead");
}
// second attempt – finalize will not run again
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no, i am dead");
}
}
}Running the program shows that the first object can rescue itself once, but the second attempt fails because finalize() is invoked at most once by the JVM.
6. Collecting the Method Area
The method area (or PermGen in older HotSpot) can also be garbage‑collected, though its efficiency is lower than that of the heap. The GC reclaims two kinds of data: unused constants and classes that satisfy three conditions: all instances are gone, the defining ClassLoader is reclaimed, and the java.lang.Class object is no longer referenced. Class unloading can be controlled with JVM options such as -Xnoclassgc and monitored with -verbose:class, -XX:+TraceClassLoading, and -XX:+TraceClassUnloading.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
