Sự khác biệt giữa java.lang.ref.WeakReference
và là java.lang.ref.SoftReference
gì?
Sự khác biệt giữa java.lang.ref.WeakReference
và là java.lang.ref.SoftReference
gì?
Câu trả lời:
Từ việc hiểu các tài liệu tham khảo yếu , bởi Ethan Nicholas:
Tài liệu tham khảo yếu
Một tham chiếu yếu , đơn giản chỉ là, một tham chiếu không đủ mạnh để buộc một đối tượng ở lại trong bộ nhớ. Tài liệu tham khảo yếu cho phép bạn tận dụng khả năng của người thu gom rác để xác định khả năng tiếp cận cho bạn, vì vậy bạn không phải tự làm điều đó. Bạn tạo một tài liệu tham khảo yếu như thế này:
WeakReference weakWidget = new WeakReference(widget);
và sau đó ở nơi khác trong mã bạn có thể sử dụng
weakWidget.get()
để lấyWidget
đối tượng thực tế . Tất nhiên, tham chiếu yếu không đủ mạnh để ngăn chặn việc thu gom rác, vì vậy bạn có thể tìm thấy (nếu không có tham chiếu mạnh đến tiện ích)weakWidget.get()
đột nhiên bắt đầu quay lạinull
....
Tài liệu tham khảo mềm
Một tài liệu tham khảo mềm giống hệt như một tài liệu tham khảo yếu, ngoại trừ việc nó ít háo hức vứt bỏ đối tượng mà nó đề cập đến. Một đối tượng chỉ có thể tiếp cận yếu (tham chiếu mạnh nhất đến nó
WeakReferences
) sẽ bị loại bỏ ở chu kỳ thu gom rác tiếp theo, nhưng một đối tượng có thể tiếp cận nhẹ thường sẽ tồn tại trong một thời gian.
SoftReferences
không bắt buộc phải cư xử khác hơnWeakReferences
, nhưng trong thực tế, các vật thể có thể tiếp cận nhẹ thường được giữ lại miễn là bộ nhớ được cung cấp dồi dào. Điều này làm cho chúng trở thành một nền tảng tuyệt vời cho bộ đệm, chẳng hạn như bộ đệm hình ảnh được mô tả ở trên, vì bạn có thể để bộ thu gom rác lo lắng về cả hai đối tượng có thể tiếp cận như thế nào (một đối tượng có thể tiếp cận mạnh sẽ không bao giờ bị xóa khỏi bộ đệm) và nó tệ đến mức nào cần bộ nhớ họ đang tiêu thụ.
Và Peter Kessler đã thêm vào một bình luận:
Sun JRE đối xử với SoftReferences khác với WeakReferences. Chúng tôi cố gắng giữ đối tượng được tham chiếu bởi SoftReference nếu không có áp lực lên bộ nhớ khả dụng. Một chi tiết: chính sách dành cho JRE "-client" và "-server" là khác nhau: JRE -client cố gắng giữ dấu chân của bạn nhỏ bằng cách thích xóa SoftReferences thay vì mở rộng heap, trong khi JRE của máy chủ cố gắng giữ cho bạn hiệu suất cao bằng cách thích mở rộng vùng heap (nếu có thể) thay vì xóa SoftReferences. Một kích thước không phù hợp với tất cả.
Tài liệu tham khảo yếu được thu thập háo hức. Nếu GC thấy rằng một đối tượng có thể truy cập yếu (chỉ có thể truy cập thông qua các tham chiếu yếu), nó sẽ xóa các tham chiếu yếu đến đối tượng đó ngay lập tức. Như vậy, chúng tốt cho việc giữ tham chiếu đến một đối tượng mà chương trình của bạn cũng giữ (tham chiếu mạnh mẽ) "thông tin liên quan" theo cách nào đó, như thông tin phản ánh được lưu trong bộ nhớ cache về một lớp hoặc trình bao bọc cho một đối tượng, v.v. không có ý nghĩa gì để giữ sau khi đối tượng mà nó được liên kết là GC-ed. Khi tham chiếu yếu bị xóa, nó sẽ bị mê hoặc trong hàng đợi tham chiếu mà mã của bạn bỏ phiếu ở đâu đó và nó cũng loại bỏ các đối tượng liên quan. Đó là, bạn giữ thêm thông tin về một đối tượng, nhưng thông tin đó không cần thiết một khi đối tượng mà nó đề cập đến biến mất. Thực ra, trong một số trường hợp nhất định, bạn thậm chí có thể phân lớp WeakReference và giữ thông tin bổ sung liên quan về đối tượng trong các trường của lớp con WeakReference. Một cách sử dụng điển hình khác của WeakReference là kết hợp với Bản đồ để giữ các trường hợp chính tắc.
Mặt khác, SoftReferences rất tốt cho việc lưu trữ các tài nguyên bên ngoài, có thể tái tạo vì GC thường trì hoãn việc xóa chúng. Mặc dù được đảm bảo rằng tất cả SoftReferences sẽ bị xóa trước khi OutOfMemoryError bị ném, vì vậy về mặt lý thuyết chúng không thể gây ra OOME [*].
Ví dụ trường hợp sử dụng điển hình là giữ một dạng nội dung được phân tích cú pháp từ một tệp. Bạn sẽ triển khai một hệ thống trong đó bạn tải một tệp, phân tích cú pháp và giữ SoftReference cho đối tượng gốc của biểu diễn được phân tích cú pháp. Lần tới khi bạn cần tệp, bạn sẽ cố truy xuất tệp thông qua SoftReference. Nếu bạn có thể truy xuất nó, bạn đã bỏ qua cho mình một tải / phân tích khác và nếu GC xóa nó trong lúc này, bạn tải lại nó. Bằng cách đó, bạn sử dụng bộ nhớ miễn phí để tối ưu hóa hiệu suất, nhưng không gặp rủi ro OOME.
Bây giờ cho [*]. Giữ một SoftReference không thể tự gây ra một OOME. Mặt khác, nếu bạn sử dụng nhầm SoftReference cho một tác vụ thì WeakReference sẽ được sử dụng (cụ thể là, bạn giữ thông tin được liên kết với một đối tượng nào đó được tham chiếu mạnh mẽ và loại bỏ nó khi đối tượng Tham chiếu bị xóa), bạn có thể chạy vào OOME như mã của bạn thăm dò ReferenceQueue và loại bỏ các đối tượng liên quan có thể xảy ra để không chạy đúng lúc.
Vì vậy, quyết định phụ thuộc vào việc sử dụng - nếu bạn lưu trữ thông tin tốn kém để xây dựng, nhưng dù sao cũng có thể được cấu trúc lại từ dữ liệu khác, hãy sử dụng các tham chiếu mềm - nếu bạn đang giữ một tham chiếu đến một thể hiện chính tắc của một số dữ liệu hoặc bạn muốn có một tham chiếu đến một đối tượng mà không "sở hữu" nó (do đó ngăn không cho nó trở thành GC'd), sử dụng một tham chiếu yếu.
WeakReference
là ở những nơi mà người ta nên sử dụng nó, thực tế là người ta có thể vẫn còn hiệu lực trong một thời gian sau khi tham chiếu vượt quá phạm vi có thể được chấp nhận, nhưng không được mong muốn.
WeakReference
là quan sát các lần chạy của GC. Xem chi tiết: stackoverflow.com/a/46291143/632951
Trong Java ; thứ tự từ mạnh nhất đến yếu nhất, có: Mạnh, Mềm, Yếu và Phantom
Một tài liệu tham khảo mạnh mẽ là một tài liệu tham khảo bình thường để bảo vệ các đối tượng được gọi từ bộ sưu tập bằng phương pháp GC. tức là không bao giờ rác thu gom.
Một mềm tham khảo là đủ điều kiện cho việc thu thập bằng cách thu gom rác, nhưng có lẽ sẽ không được thu thập cho đến khi bộ nhớ của nó là cần thiết. tức là rác thu gom trước OutOfMemoryError
.
Một tài liệu tham khảo Yếu là một tài liệu tham khảo mà không bảo vệ một đối tượng tham chiếu từ bộ sưu tập bằng phương pháp GC. tức là rác thu gom khi không có ref mạnh hay mềm.
Một Phantom tham khảo là một tham chiếu đến một đối tượng được phantomly tham chiếu sau khi nó đã được hoàn tất, nhưng trước khi cấp phát bộ nhớ của nó đã được khai hoang.
Tương tự: Giả sử JVM là một vương quốc, Object là một vị vua của vương quốc và GC là kẻ tấn công của vương quốc, người cố gắng giết vua (đối tượng).
until memory is available
không có ý nghĩa. Ý bạn là is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
sao
Tham khảo yếu http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Nguyên tắc: weak reference
có liên quan đến việc thu gom rác. Thông thường, đối tượng có một hoặc nhiều reference
sẽ không đủ điều kiện để thu gom rác.
Nguyên tắc trên không được áp dụng khi có weak reference
. Nếu một đối tượng chỉ có tham chiếu yếu với các đối tượng khác, thì đối tượng đó đã sẵn sàng để thu gom rác.
Hãy xem ví dụ dưới đây: Chúng ta có một Map
đối tượng trong đó Key là tham chiếu một đối tượng.
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> aMap = new
HashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
System.out.println("Size of Map" + aMap.size());
}
}
Bây giờ, trong quá trình thực hiện chương trình chúng tôi đã thực hiện emp = null
. Việc Map
giữ chìa khóa không có ý nghĩa gì ở đây null
. Trong tình huống trên, đối tượng không được thu gom rác.
Bản đồ yếu
WeakHashMap
là một trong đó các mục ( key-to-value mappings
) sẽ bị xóa khi không thể truy xuất chúng từ Map
.
Hãy để tôi hiển thị ví dụ trên giống với WeakHashMap
import java.util.WeakHashMap;
public class Test {
public static void main(String args[]) {
WeakHashMap<Employee, EmployeeVal> aMap =
new WeakHashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
int count = 0;
while (0 != aMap.size()) {
++count;
System.gc();
}
System.out.println("Took " + count
+ " calls to System.gc() to result in weakHashMap size of : "
+ aMap.size());
}
}
Đầu ra: Lấy 20 calls to System.gc()
kết quả aMap size
là: 0.
WeakHashMap
chỉ tham chiếu yếu đến các khóa, không tham chiếu mạnh như các Map
lớp khác . Có những tình huống mà bạn phải quan tâm khi giá trị hoặc khóa được tham chiếu mạnh mẽ mặc dù bạn đã sử dụng WeakHashMap
. Điều này có thể tránh được bằng cách bọc đối tượng trong WeakReference .
import java.lang.ref.WeakReference;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> map =
new HashMap<Employee, EmployeeVal>();
WeakReference<HashMap<Employee, EmployeeVal>> aMap =
new WeakReference<HashMap<Employee, EmployeeVal>>(
map);
map = null;
while (null != aMap.get()) {
aMap.get().put(new Employee("Vinoth"),
new EmployeeVal("Programmer"));
System.out.println("Size of aMap " + aMap.get().size());
System.gc();
}
System.out.println("Its garbage collected");
}
}
Tài liệu tham khảo mềm.
Soft Reference
mạnh hơn một chút mà tham chiếu yếu. Tham chiếu mềm cho phép thu gom rác, nhưng cầu xin người thu gom rác chỉ xóa nếu không có tùy chọn nào khác.
Trình thu gom rác không tích cực thu thập các đối tượng có thể tiếp cận nhẹ nhàng như cách thực hiện với các đối tượng có thể tiếp cận yếu - thay vào đó, nó chỉ thu thập các đối tượng có thể tiếp cận nhẹ nếu thực sự "cần" bộ nhớ. Tài liệu tham khảo mềm là một cách để nói với người thu gom rác, "Miễn là bộ nhớ không quá chật, tôi muốn giữ vật này xung quanh. Nhưng nếu bộ nhớ trở nên rất chật, hãy tiếp tục và thu thập nó và tôi sẽ giải quyết với." Bộ thu gom rác được yêu cầu xóa tất cả các tham chiếu mềm trước khi có thể ném OutOfMemoryError
.
NullPointerException
trong aMap.get().put(...)
.
WeakHashMap
ví dụ (vì đó là ví dụ đầu tiên thể hiện hành vi yếu). Xem tài liệu cho "WeakHashMap": "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. "
Toàn bộ quan điểm của việc sử dụng WeakHashMap là bạn không phải khai báo / truyền vào WeakReference; WeakHashMap làm điều đó cho bạn, trong nội bộ. docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
WeakHashMap
hoạt động, với ứng dụng ví dụ chỉ ra cách loại bỏ các mục sau khi thực thi bộ sưu tập rác, hãy xem Câu trả lời của tôi cho câu hỏi, WeakHashMap có phát triển không, hay nó có xóa các khóa rác không? .
Sự khác biệt thực sự duy nhất giữa một tham chiếu mềm và một tham chiếu yếu là
trình thu gom rác sử dụng các thuật toán để quyết định có thu hồi một đối tượng có thể tiếp cận nhẹ hay không, nhưng luôn lấy lại một đối tượng có thể tiếp cận yếu.
SoftReference
được thiết kế cho bộ nhớ cache. Khi phát hiện ra rằng một WeakReference
tham chiếu một đối tượng không thể truy cập khác, thì nó sẽ bị xóa ngay lập tức. SoftReference
có thể để lại như vậy. Thông thường, có một số thuật toán liên quan đến dung lượng bộ nhớ trống và thời gian sử dụng cuối cùng để xác định xem có nên xóa nó hay không. Thuật toán Sun hiện tại là xóa tham chiếu nếu nó không được sử dụng trong nhiều giây vì có megabyte bộ nhớ miễn phí trên heap Java (có thể cấu hình, máy chủ HotSpot kiểm tra đối với heap tối đa có thể được thiết lập bởi -Xmx
). SoftReference
s sẽ bị xóa trước khi OutOfMemoryError
ném, trừ khi có thể tiếp cận.
java.lang
. Lạm dụng từ đồng nghĩa như vậy là không làm ai tốt cả.
Bài viết này có thể siêu hữu ích để hiểu các tài liệu tham khảo mạnh, mềm, yếu và ảo.
Để cho bạn một bản tóm tắt,
Nếu bạn chỉ có các tham chiếu yếu đến một đối tượng (không có tham chiếu mạnh), thì đối tượng đó sẽ được thu hồi bởi GC trong chu trình GC tiếp theo.
Nếu bạn chỉ có các tham chiếu mềm đến một đối tượng (không có tham chiếu mạnh), thì đối tượng đó sẽ chỉ được thu hồi bởi GC khi JVM hết bộ nhớ.
Vì vậy, bạn có thể nói rằng, các tài liệu tham khảo mạnh mẽ có sức mạnh tối thượng (không bao giờ có thể được thu thập bởi GC)
Tham chiếu mềm mạnh hơn tham chiếu yếu (vì chúng có thể thoát khỏi chu trình GC cho đến khi JVM hết bộ nhớ)
Các tham chiếu yếu thậm chí còn kém mạnh hơn các tham chiếu mềm (vì chúng không thể trích xuất bất kỳ chu trình GC nào và sẽ được thu hồi nếu đối tượng không có tham chiếu mạnh nào khác).
Nhà hàng tương tự
Bây giờ nếu bạn là một khách hàng mạnh (tương tự như tham chiếu mạnh), thì ngay cả khi một khách hàng mới đến nhà hàng hoặc những gì đã từng xảy ra, bạn sẽ không bao giờ rời khỏi bàn của mình (vùng nhớ trên đống). Người phục vụ không có quyền bảo bạn (hoặc thậm chí yêu cầu bạn) rời khỏi nhà hàng.
Nếu bạn là một khách hàng mềm (tương tự như tham chiếu mềm), thì nếu một khách hàng mới đến nhà hàng, người phục vụ sẽ không yêu cầu bạn rời khỏi bàn trừ khi không còn bàn trống nào khác để chứa khách hàng mới. (Nói cách khác, người phục vụ sẽ yêu cầu bạn rời khỏi bàn chỉ khi một khách hàng mới bước vào và không còn bàn nào khác cho khách hàng mới này)
Nếu bạn là một khách hàng yếu (tương tự như tham chiếu yếu), thì người phục vụ, theo ý muốn của anh ta, có thể (bất cứ lúc nào) yêu cầu bạn rời khỏi nhà hàng: P
Theo tài liệu , WeakReferences lỏng lẻo phải được xóa bởi một GC đang chạy.
Theo tài liệu , SoftReferences lỏng lẻo phải được xóa trước khi ném OOM.
Đó là sự khác biệt thực sự duy nhất. Mọi thứ khác không phải là một phần của hợp đồng. (Tôi sẽ cho rằng các tài liệu mới nhất là hợp đồng.)
SoftReferences là hữu ích. Bộ nhớ cache nhạy cảm với bộ nhớ sử dụng SoftReferences, không phải WeakReferences.
weak_ref.get()
. Khi đó null
, bạn biết rằng trong khoảng thời gian này, GC đã chạy.
Đối với việc sử dụng WeakReference không chính xác , danh sách này là vô tận:
một bản hack tệ hại để thực hiện phần mềm ưu tiên 2 để bạn không phải viết một bản, nhưng nó không hoạt động như mong đợi vì bộ nhớ cache sẽ bị xóa trong mỗi lần chạy GC, ngay cả khi có bộ nhớ dự phòng. Xem https://stackoverflow.com/a/3243242/632951 để biết các phails. (Bên cạnh đó, nếu bạn cần nhiều hơn 2 cấp độ ưu tiên bộ đệm thì bạn vẫn cần một thư viện thực sự cho nó.)
một hack tệ hại để liên kết dữ liệu với một đối tượng của một lớp hiện có, nhưng nó tạo ra sự rò rỉ bộ nhớ (OutOfMemoryError) khi GC của bạn quyết định nghỉ sau khi các điểm yếu của bạn được tạo. Bên cạnh đó, nó còn vượt trội: Một cách tiếp cận tốt hơn là sử dụng bộ dữ liệu.
một hack tệ hại để liên kết dữ liệu với một đối tượng của một lớp hiện có, trong đó lớp có dây thần kinh để làm cho nó không thể phân lớp và được sử dụng trong một mã chức năng hiện có mà bạn cần gọi. Trong trường hợp như vậy, giải pháp thích hợp là chỉnh sửa lớp và biến nó thành lớp con, hoặc chỉnh sửa hàm và làm cho nó có giao diện thay vì lớp hoặc sử dụng hàm thay thế.
equals()
chỉ là nhận dạng đối tượng? Tài liệu tham khảo mềm có vẻ như là một sự lãng phí ở đó, bởi vì một khi một đối tượng quan trọng không còn có thể tiếp cận mạnh mẽ, sẽ không ai tìm kiếm bản đồ đó nữa.
Sáu loại trạng thái khả năng tiếp cận đối tượng trong Java:
Để biết thêm chi tiết: https://www.artima.com/insidejvm/ed2/gc16.html «sụp đổ
Mọi người nên biết rằng một đối tượng được tham chiếu yếu sẽ chỉ được thu thập khi nó chỉ có (các) tham chiếu yếu. Nếu nó có quá nhiều tài liệu tham khảo mạnh, thì nó không được thu thập cho dù có bao nhiêu tài liệu tham khảo yếu.
Để đưa ra khía cạnh sử dụng bộ nhớ trong thực tế, tôi đã thử nghiệm với các tham chiếu Mạnh, Mềm, Yếu & Phantom dưới tải nặng với các vật nặng bằng cách giữ chúng cho đến khi kết thúc chương trình. Sau đó theo dõi hành vi sử dụng heap & GC . Các số liệu này có thể thay đổi tùy theo từng trường hợp nhưng chắc chắn mang lại sự hiểu biết cao. Dưới đây là những phát hiện.
Hành vi của Heap & GC dưới tải nặng
Bạn có thể nhận được nhiều hơn về đồ thị, số liệu thống kê, quan sát cho thí nghiệm này ở đây .
WeakReference : các đối tượng chỉ được tham chiếu yếu được thu thập ở mỗi chu kỳ GC (nhỏ hoặc đầy đủ).
SoftReference : khi các đối tượng chỉ được tham chiếu nhẹ được thu thập tùy thuộc vào:
-XX: SoftRefLRUPolicyMSPerMB = N cờ (giá trị mặc định là 1000, còn gọi là 1 giây)
Số lượng bộ nhớ miễn phí trong heap.
Thí dụ:
Sau đó, đối tượng chỉ được tham chiếu bởi SoftReference sẽ được thu thập nếu lần cuối cùng khi nó được truy cập lớn hơn 10 giây.