99 Ngày Java — Ngày 76: Soft, Weak và Phantom Reference
Biến trỏ tới đối tượng không phải lúc nào cũng giữ đối tượng sống mãi. Java có strong, soft, weak và phantom reference để biểu đạt các mức reachability. Chúng hữu ích khi làm cấu trúc phụ trợ hoặc theo dõi vòng đời đối tượng, nhưng không thay thế chính sách cache rõ ràng.

1. Strong và soft: giữ chắc hay nhường khi thiếu bộ nhớ
Tham chiếu thường là strong: chừng nào còn đường đi từ GC root, đối tượng chưa được thu gom. SoftReference chỉ giữ đối tượng khi JVM còn muốn giữ; GC có thể xóa nó theo nhu cầu bộ nhớ. Thời điểm xóa không phải hợp đồng về TTL hay dung lượng, vì thế cache production nên đặt giới hạn theo số phần tử hoặc trọng lượng.
byte[] value = new byte[1024];
var soft = new java.lang.ref.SoftReference<>(value);
value = null; // now only the soft reference may retain it
byte[] maybe = soft.get(); // may be null2. WeakReference và WeakHashMap
Nếu đối tượng chỉ còn weak reference, GC có thể thu nó ở lần quét kế tiếp. WeakHashMap giữ key bằng weak reference; khi key không còn được giữ mạnh ở nơi khác, entry có thể biến mất. Nhưng value giữ ngược key sẽ tạo đường strong qua map và phá mục tiêu. Đừng dựa vào thời điểm entry biến mất để viết logic nghiệp vụ.
var metadata = new java.util.WeakHashMap<Object, String>();
Object key = new Object();
metadata.put(key, "debug-only");
key = null; // entry becomes eligible for removal; no timing promise3. PhantomReference và ReferenceQueue
PhantomReference.get() luôn trả null; nó không dùng để lấy lại đối tượng. Kết hợp với ReferenceQueue, nó báo khi đối tượng đã đạt trạng thái có thể dọn dẹp; ứng dụng vẫn phải giữ chính đối tượng PhantomReference để nhận thông báo. Với tài nguyên ngoài heap, ưu tiên AutoCloseable và try-with-resources; Cleaner chỉ là đường dự phòng, không bảo đảm chạy đúng lúc.
var queue = new java.lang.ref.ReferenceQueue<Object>();
Object target = new Object();
var phantom = new java.lang.ref.PhantomReference<>(target, queue);
target = null;
// Later: queue.remove() can yield phantom; phantom.get() is always null.4. Chọn công cụ theo hợp đồng
Strong cho dữ liệu phải tồn tại; weak cho metadata đi theo vòng đời key; phantom cho tín hiệu dọn dẹp cuối vòng đời. Soft chỉ là một gợi ý cho GC, không phải bộ nhớ đệm có kiểm soát. Dù chọn loại nào, hãy kiểm tra null sau get(), đo cache hit và dùng heap dump nếu nghi key hoặc value bị giữ ngoài ý muốn.
Cache cần giới hạn rõ và chính sách loại bỏ; không phó mặc cho GC.
Tài nguyên phải đóng chủ động bằng try-with-resources.
Mức tham chiếu là hợp đồng reachability, không phải lịch GC. Ngày 77 xem một nơi khác JVM chia sẻ chuỗi: String pool và intern().
Tài liệu đối chiếu
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ref/package-summary.html
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/WeakHashMap.html
Site Admin
Engineer and writer. Building things with TypeScript and distributed systems.
Bình luận (0)
Bạn cần đăng nhập bằng Google để bình luận.
Hãy là người bình luận đầu tiên.
