Hiểu các lớp tham chiếu của Java: SoftReference, WeakReference và PhantomReference


81

Ai đó có thể giải thích sự khác biệt giữa ba lớp Tham chiếu (hoặc đăng một liên kết đến một lời giải thích hay)? SoftReference> WeakReference> PhantomReference, Nhưng khi tôi sẽ sử dụng mỗi người? Tại sao có WeakHashMapnhưng không có SoftHashMaphoặc PhantomHashMap?

Và nếu tôi sử dụng mã sau ...

WeakReference<String> ref = new WeakReference<String>("Hello!");
if (ref != null) {                 // ref can get collected at any time...
    System.gc();                   // Let's assume ref gets collected here.
    System.out.println(ref.get()); // Now what?!
}

... chuyện gì xảy ra? Tôi có phải kiểm tra xem reflà null trước mỗi statement (điều này là sai, nhưng những gì nên tôi làm)? Xin lỗi vì câu hỏi quá nhanh, nhưng tôi đang gặp khó khăn khi hiểu các Referencelớp này ... Cảm ơn!


1
Tại sao có câu hỏi WeakHashMapnhưng không SoftHashMaphoặc PhantomHashMapxuất sắc, tại sao tôi không nhận thấy điều này trước đây .. ??
Mehraj Malik

1
Các ref != nullkiểm tra làm cho không có ý nghĩa. refsẽ không bao giờ null.
Holger

thêm vào Q: strongRef --> weakRef --> objA. Bây giờ, di chúc objAsẽ được GCed hoặc không, vì nó có một tham chiếu gián tiếp từ strongRef.
Samshers

Câu trả lời:


60

Tài liệujava.lang.ref thư viện Java cho gói mô tả độ mạnh giảm dần của ba kiểu tham chiếu rõ ràng.

Bạn sử dụng một SoftReferencekhi bạn muốn đối tượng được tham chiếu vẫn tồn tại cho đến khi tiến trình máy chủ sắp hết bộ nhớ. Đối tượng sẽ không đủ điều kiện để thu thập cho đến khi bộ sưu tập cần giải phóng bộ nhớ. Nói một cách lỏng lẻo, ràng buộc một SoftReferencephương tiện, "Ghim đối tượng cho đến khi bạn không thể nữa."

Ngược lại, hãy sử dụng một WeakReferencekhi bạn không muốn ảnh hưởng đến thời gian tồn tại của đối tượng được tham chiếu; bạn chỉ muốn đưa ra một xác nhận riêng về đối tượng được tham chiếu, miễn là nó vẫn còn tồn tại. Tính đủ điều kiện thu thập của đối tượng không bị ảnh hưởng bởi sự hiện diện của các ràng buộc WeakReference. Một cái gì đó giống như ánh xạ bên ngoài từ cá thể đối tượng đến thuộc tính liên quan, trong đó thuộc tính chỉ cần được ghi lại miễn là đối tượng liên quan còn sống, là một cách sử dụng tốt cho WeakReferences và WeakHashMap.

Cái cuối PhantomReferencecùng— — khó mô tả hơn. Giống như WeakReference, một ràng buộc như vậy PhantomReferencekhông ảnh hưởng đến thời gian tồn tại của đối tượng được tham chiếu. Nhưng không giống như các loại tham chiếu khác, thậm chí không thể bỏ qua tham chiếu a PhantomReference. Theo một nghĩa nào đó, nó không hướng đến thứ mà nó chỉ đến, theo như những gì người gọi có thể nói. Nó chỉ cho phép người ta liên kết một số dữ liệu liên quan với đối tượng được tham chiếu — dữ liệu sau này có thể được kiểm tra và xử lý khi đối tượng PhantomReferenceđược xếp hàng đợi trong liên quan của nó ReferenceQueue. Thông thường người ta dẫn xuất một kiểu từ PhantomReferencevà bao gồm một số dữ liệu bổ sung trong kiểu dẫn xuất đó. Thật không may, có một số dự báo giảm liên quan đến việc sử dụng loại có nguồn gốc như vậy.

Trong mã ví dụ của bạn, nó không phải là reftham chiếu (hoặc, nếu bạn thích, "biến") có thể là rỗng. Đúng hơn, đó là giá trị thu được bằng cách gọi Reference#get()có thể là null. Nếu nó được tìm thấy là null, bạn đã quá muộn; đối tượng được tham chiếu đang trên đường được thu thập:

final String val = ref.get();
if (null != val)
{
  // "val" is now pinned strongly.
}
else
{
  // "val" is already ready to be collected.
}

thêm vào Q: strongRef --> weakRef --> objA. Bây giờ, di chúc objAsẽ được GCed hoặc không, vì nó có một tham chiếu gián tiếp từ strongRef.
Samshers

Nếu tôi hiểu câu hỏi của bạn một cách chính xác, @samshers, objAđủ điều kiện để thu thập làm rác. Việc ghim một WeakReferencekhông ảnh hưởng đến đối tượng mà nó WeakReferencetrỏ đến.
seh

Không có một tham chiếu mạnh mẽ trong chuỗi tạo ra sự khác biệt. Bởi vì objAđể được thu thập rác, tham chiếu yếu phải được loại bỏ trước tiên phải. Và một tham chiếu mạnh đang trỏ đến tham chiếu yếu khiến cho tham chiếu yếu không đủ điều kiện để được GCed
Samshers

Không, WeakReferencekhông cần phải thu thập để cho phép objAthu thập. Các WeakReferencekhông giữ objAcòn sống. Đúng hơn, đó là một cách để tìm objAkhi nó còn sống — mà không ảnh hưởng đến thời gian tồn tại — và phát hiện khi nào người sưu tập đã lấy nó đi.
seh

6

Một liên kết: https://community.oracle.com/blogs/enicholas/2006/05/04/undilities-weak-references

PhantomHashMapsẽ không hoạt động tốt vì getluôn trả về nullcho các tham chiếu ma.

Bộ nhớ đệm rất khó, vì vậy SoftHashMapcó thể không hoạt động tốt như bạn nghĩ. Tuy nhiên, tôi tin rằng thư viện bộ sưu tập của Google có triển khai bản đồ tham chiếu chung.

Bạn nên luôn kiểm tra xem có gettrả về không null. (Lưu ý rằng việc không kiểm tra xem Referencebản thân tham chiếu có phải là không- null.) Trong trường hợp chuỗi interned thì nó sẽ luôn như vậy, nhưng (như bao giờ hết) đừng cố tỏ ra "thông minh" về nó.


Liên kết đã hết hạn.
Mehraj Malik,

Liên kết @MehrajMalik đã sửa.
Tom Hawtin - tackline

thêm vào Q: strongRef --> weakRef --> objA. Bây giờ, di chúc objAsẽ được GCed hoặc không, vì nó có một tham chiếu gián tiếp từ strongRef.
Samshers


0
String str = new String("hello, world");
WeakReference<String> ref = new WeakReference<String>(str);
str = null;

if (ref != null) {                 
    System.gc(); 
    System.out.println(ref.get());
}

Trong trường hợp này, nó sẽ xuất ra null. Cuộc gọi đến System.gc()là quan trọng ở đây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.