Garbage Collection - Quiz
Total: 6 questions
1. When does an object become eligible for garbage collection in Java, and what are GC roots?
When does an object become eligible for garbage collection in Java, and what are GC roots?
An object becomes garbage when it can no longer be reached through any chain of references starting from a garbage collection root (GC root). The roots are: local variables and method parameters on the stacks of all live threads, static fields of loaded classes, live Thread objects themselves, references from native code (JNI), and objects used as synchronization monitors. An important consequence of the reachability model is that cyclic references do not prevent collection. If two objects reference each other but neither can be reached from a GC root, they form an «island of isolation» and are collected as a whole. This is the key difference from reference counting, where such a cycle would stay in memory forever. Assigning obj = null does not delete the object by itself — it only removes one reference; the memory is reclaimed by the garbage collector, and only if no other references remain.
2. Does calling System.gc() guarantee that garbage collection runs?
Does calling System.gc() guarantee that garbage collection runs?
No. System.gc() is only a hint to the virtual machine, not a command. The JVM may run a full collection, may run it later, or may ignore the call entirely. Runtime.getRuntime().gc() is equivalent — System.gc() simply delegates to it. On top of that, an application can be started with -XX:+DisableExplicitGC, which turns every explicit System.gc() call into a no-op. You should not call System.gc() in application code: it usually triggers an expensive stop-the-world full collection and makes behaviour worse rather than better. Legitimate uses are teaching examples, microbenchmarks and measuring memory before taking a heap dump.
3. Why was the finalize() method deprecated, and what should be used instead?
Why was the finalize() method deprecated, and what should be used instead?
Finalization accumulated too many problems: an unpredictable delay between the moment an object becomes garbage and the moment the method runs; the risk of OutOfMemoryError caused by a growing finalization queue (an object with finalize() survives at least one extra collection); exceptions thrown from finalize() are silently swallowed; an object can be resurrected by storing this in a static field; races and the classic finalizer attack; and a noticeable overhead when allocating and collecting such objects. Timeline: Java 9 marked the method @Deprecated and added java.lang.ref.Cleaner, Java 11 removed System.runFinalizersOnExit(), and Java 18 (JEP 421) marked finalization deprecated for removal and introduced the --finalization=disabled flag. The replacement: the primary tool is deterministic cleanup via AutoCloseable and try-with-resources, while Cleaner serves only as a safety net for the case where close() was never called. The single guarantee the specification gives for finalize() is that if it runs at all, it runs at most once per object.
4. What is the difference between strong, soft, weak and phantom references in Java?
What is the difference between strong, soft, weak and phantom references in Java?
The java.lang.ref package lets you control how strongly a reference keeps an object alive. A strong reference (an ordinary reference, there is no dedicated class) never lets the object be collected while the reference itself is reachable from a GC root — this is all normal code. A soft reference (SoftReference) lets the object be cleared when memory runs low, before an OutOfMemoryError is thrown; it suits caches you can afford to lose. A weak reference (WeakReference) lets the object be cleared at the very next collection if no strong references exist; it is used by WeakHashMap, metadata and listeners. A phantom reference (PhantomReference) always returns null from get(), so the object can never be resurrected; the notification arrives in a ReferenceQueue after the object has been found unreachable. The Cleaner class is built on phantom references, and it is what you should use instead of handling the queue yourself.
5. Which garbage collectors does the HotSpot JVM offer, and which one is used by default?
Which garbage collectors does the HotSpot JVM offer, and which one is used by default?
Since Java 9 the default collector is G1 (Garbage-First, -XX:+UseG1GC): the heap is split into regions and you set a target pause time, which suits most server applications. Java 8 used Parallel GC by default, and on a small machine JVM ergonomics may still pick Serial GC. The other options are: -XX:+UseSerialGC — single-threaded with minimal overhead, for a small heap or a single-core container; -XX:+UseParallelGC — maximum throughput at the cost of long pauses, for batch processing; -XX:+UseZGC — sub-millisecond pauses on multi-terabyte heaps, for latency-sensitive services; -XX:+UseShenandoahGC — heap compaction concurrent with the running application; -XX:+UseEpsilonGC — collects nothing and simply runs out of memory, useful for benchmarks. You can check which one is active with java -XX:+PrintFlagsFinal -version or in the startup log using -Xlog:gc.
6. Can a Java application leak memory even though it has a garbage collector?
Can a Java application leak memory even though it has a garbage collector?
Yes. The garbage collector only reclaims unreachable objects, so a memory leak in Java is an object that is no longer needed but is still reachable from a GC root. Typical sources are growing static collections, caches without eviction, listeners that were never unsubscribed, a ThreadLocal held by a pooled thread, a key in a HashMap with broken equals() and hashCode(), and unclosed resources. Such leaks are diagnosed from a heap dump in VisualVM or Eclipse MAT, or through Java Flight Recorder. Remember as well that the garbage collector manages the heap only: since Java 8 class metadata lives in Metaspace, and memory allocated through ByteBuffer.allocateDirect() or JNI is off-heap, so the GC does not release it directly.