Object đủ điều kiện thu hồi khi không còn đường đi tới nó từ GC root nào. GC root gồm: biến local trên stack của thread đang sống, static field, tham chiếu từ JNI, và chính các thread đang chạy.
Đây là reachability, không phải đếm số tham chiếu. Nên hai object trỏ vòng vào nhau mà không ai từ ngoài trỏ tới thì vẫn bị thu hồi:
Node a = new Node(), b = new Node();
a.next = b;
b.next = a; // tham chiếu vòng
a = null;
b = null; // cả cụm không còn tới được từ root -> thu hồi đượcGán null hay biến ra khỏi scope chỉ cắt một tham chiếu; nếu còn chỗ khác giữ (một static Map, một listener chưa gỡ) thì object vẫn sống — đó là dạng memory leak phổ biến nhất trong Java.
System.gc() chỉ là gợi ý. Javadoc ghi rõ JVM được phép bỏ qua, và nhiều hệ thống production còn chạy với -XX:+DisableExplicitGC để biến nó thành no-op. Không có API nào ép GC chạy ngay; code không nên phụ thuộc vào thời điểm GC diễn ra.