ExerciseWarm-up
Warm-up
Two objects, one collected
5 minintermediate2–8 yrs
One concept, guided. Near-impossible to fail.
What this teaches
- The collector frees what is unreachable, not what you have finished with
- A static field is a GC root, so anything it reaches lives for the process
- A WeakReference is a probe for exactly the property that decides collection
Starter
Starter.javaOpen in playground
import java.lang.ref.*;
import java.util.*;
/**
* WARM-UP — 5 minutes. One concept. Hard to fail.
*
* Two identical objects. Both have their local variable set to null. One is
* collected and one is not.
*
* TASKS
* 1. Predict both answers before running.
* 2. Run it.
* 3. In a comment: nothing about the two objects differs. So what does?
* 4. Add one line before the second probe so that it is collected too.
*/
public class Starter {
/** A static field. Its class is a GC root, and classes are not unloaded. */
static final List<Object> CACHE = new ArrayList<>();
public static void main(String[] args) {
Object loose = new Object();
WeakReference<Object> probe1 = new WeakReference<>(loose);
loose = null;
System.out.println("no other reference : collected = " + collected(probe1));
Object cached = new Object();
WeakReference<Object> probe2 = new WeakReference<>(cached);
CACHE.add(cached);
cached = null;
// TASK 4: one line here makes the next line print true.
System.out.println("added to CACHE : collected = " + collected(probe2));
System.out.println("CACHE.size() : " + CACHE.size());
// Question to answer in a comment before you move on:
// CACHE is `final`. Does that have anything to do with why the second
// object survived? If not, what would?
}
/**
* System.gc() is a hint, not a command, so asking once proves nothing.
* This asks repeatedly with allocation pressure in between, and gives up
* after a bounded number of attempts so it cannot hang.
*/
static boolean collected(WeakReference<?> ref) {
for (int attempt = 0; attempt < 50 && ref.get() != null; attempt++) {
System.gc();
byte[] churn = new byte[1 << 20];
if (churn.length < 0) System.out.print("");
}
return ref.get() == null;
}
}Run it locally:
cd exercises/java/jvm/memory-leaks/01-warmup
javac Starter.java -d /tmp/out && java -cp /tmp/out StarterDone when
- You predicted which probe would clear before running
- A comment explains what is different about the two objects — and it is not the objects
- You made the second one collectable with a one-line change
← Back to How do you get a memory leak in a garbage-collected language?