Java: sự khác biệt giữa tham chiếu mạnh / mềm / yếu / ảo


178

Tôi đã đọc bài viết này về chủ đề này, nhưng tôi không thực sự hiểu nó. Xin vui lòng cho tôi một số lời khuyên cùng với các ví dụ khi mô tả các khái niệm.



4
Tôi đã đọc tài liệu đó, nó không giúp tôi tưởng tượng sự khác biệt. (có thể vì đó là tài liệu khó đọc)

14
Nếu bạn đọc bài viết đó mà vẫn không hiểu, bạn có câu hỏi cụ thể nào về nó không? Thật khó để trả lời "vui lòng giải thích Foo cho tôi", "đây là ý nghĩa của nó", "Tôi không hiểu" mà không có thông tin cụ thể về những phần bạn không nhận được.
yshavit


@LouisWasserman Liên kết hàng đầu không còn hiệu lực.
Mehraj Malik

Câu trả lời:


142

Java cung cấp hai loại / lớp đối tượng tham chiếu khác nhau : mạnhyếu . Đối tượng tham chiếu yếu có thể được chia thành mềmảo .

  • Mạnh
  • Yếu
    • mềm mại
    • ma

Hãy đi từng điểm một.

Đối tượng tham khảo mạnh

StringBuilder builder = new StringBuilder();

Đây là loại / lớp mặc định của Đối tượng tham chiếu, nếu không được chỉ định khác: builderlà Đối tượng tham chiếu mạnh. Loại tham chiếu này làm cho đối tượng được tham chiếu không đủ điều kiện cho GC. Đó là, bất cứ khi nào một đối tượng được tham chiếu bởi một chuỗi các Đối tượng tham chiếu mạnh , nó không thể được thu gom rác.

Đối tượng tham khảo yếu

WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);

Đối tượng tham chiếu yếu không phải là loại / lớp mặc định của Đối tượng tham chiếu và để được sử dụng, chúng phải được chỉ định rõ ràng như trong ví dụ trên. Loại tham chiếu này làm cho đối tượng tham chiếu đủ điều kiện cho GC. Đó là, trong trường hợp tham chiếu duy nhất có thể truy cập được cho StringBuilderđối tượng trong bộ nhớ, trên thực tế, là tham chiếu yếu, thì GC được phép thu gom rác StringBuilderđối tượng. Khi một đối tượng trong bộ nhớ chỉ có thể truy cập được bằng các Đối tượng tham chiếu yếu, nó sẽ tự động đủ điều kiện cho GC.

Mức độ yếu

Hai mức độ yếu khác nhau có thể được liệt kê: mềmảo .

Một mềm Object Reference cơ bản là một Object Reference yếu mà hài cốt trong bộ nhớ một cắn hơn: bình thường, nó chống lại chu kỳ GC cho đến khi không nhớ đã có sẵn và có nguy cơOutOfMemoryError (trong trường hợp đó, nó có thể được loại bỏ).

Mặt khác, Đối tượng tham chiếu ảo chỉ hữu ích khi biết chính xác khi nào một đối tượng đã được xóa khỏi bộ nhớ một cách hiệu quả: thông thường chúng được sử dụng để sửa chữa hành vi hồi sinh / hồi sinh kỳ lạ () vì chúng thực sự không trả lại đối tượng chỉ giúp theo dõi sự hiện diện bộ nhớ của họ .

Đối tượng tham chiếu yếu là lý tưởng để thực hiện các mô-đun bộ đệm. Trong thực tế, một loại trục xuất tự động có thể được thực hiện bằng cách cho phép GC dọn sạch các vùng nhớ bất cứ khi nào các đối tượng / giá trị không thể truy cập được bằng chuỗi tham chiếu mạnh. Một ví dụ là WeakHashMap giữ lại các khóa yếu.


76

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 đó.

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ó là 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.

Tham chiếu ma:

Một tham chiếu ảo khá khác so với SoftReference hoặc WeakReference. Độ bám của nó đối với đối tượng của nó rất khó để bạn thậm chí không thể truy xuất đối tượng - phương thức get () của nó luôn trả về null. Việc sử dụng duy nhất cho một tham chiếu như vậy là theo dõi khi nào nó được đưa vào ReferenceQueue, vì tại thời điểm đó, bạn biết đối tượng mà nó chỉ ra đã chết.

Văn bản này được trích xuất từ: https://weblogs.java.net/blog/2006/05/04/under Hiểu-weak-report


1
Mặc dù mọi thứ trong câu trả lời này có vẻ đúng, nhưng đối với tôi, có vẻ như có thể có lỗi trên trang web được liên kết. Các Javadoc cho gói java.lang.ref và cho PhantomReference gợi ý rằng một đối tượng không phải là thu gom rác thải cho đến sau khi nó không còn "ảo có thể truy cập", ngụ ý rằng (không giống như SoftReference) một PhantomReference phải được dequeued trước khi đối tượng nó đề cập đến lon rác được thu thập ... và nó bị mê hoặc không cho thấy rằng bộ nhớ liên quan đã được giải phóng.
Theodore Murdock

2
Đối với hồ sơ, tôi rất muốn sống trong một thế giới nơi bài đăng blog đó là chính xác.
Theodore Murdock

1
@TheodoreMurdock javadoc là chính xác. Một tham chiếu ảo không cản trở việc thu gom rác. Một khi một đối tượng bị mê hoặc, nó không thể được lưu ngay cả bởi một bộ hoàn thiện, vì các bộ hoàn thiện đã chạy. Nó đã chết, nhưng chưa biến mất.
Leliel

@Leliel Trên thực tế, một tham chiếu phantom làm trên thực tế bộ sưu tập làm ngăn trở rác sau khi được enqueued ... Tôi nhận ra điều này thời gian gần đây khi một lỗi gây ra một sợi dọn dẹp để thoát sớm. Sự tồn tại của các tham chiếu ảo là đủ để đảm bảo rằng mọi đối tượng tham chiếu ảo được giữ lại trong vùng heap của tôi, không có sẵn để thu thập ... nếu bạn không xử lý hàng đợi hoặc không thể tạo tham chiếu ảo đủ điều kiện cho gc khi xử lý hàng đợi ( và không xóa () tham chiếu ảo), sau đó rò rỉ bộ nhớ của bạn sẽ bao gồm cả tham chiếu ảo và đối tượng được tham chiếu.
Theodore Murdock

25

Sự khác biệt đơn giản giữa SoftReferenceWeakReferenceđược cung cấp bởi Nhà phát triển Android .

Sự khác biệt giữa a SoftReferencevà a WeakReferencelà thời điểm mà quyết định được đưa ra để làm rõ và ghi lại tham chiếu:

  • A SoftReferencenên được xóa và xử lý càng muộn càng tốt, trong trường hợp VM có nguy cơ hết bộ nhớ.

  • A WeakReferencecó thể bị xóa và mê hoặc ngay khi được biết là tham chiếu yếu.


16

Ba thuật ngữ mà bạn đã sử dụng hầu hết liên quan đến tính đủ điều kiện của Object để thu gom Rác.

Tham chiếu yếu :: Đây là một tham chiếu không đủ mạnh để buộc đối tượng ở lại trong bộ nhớ. Đó là ý tưởng của người thu gom rác để thu thập đối tượng đó để thu gom rác. Bạn không thể buộc GC không thu thập nó .

Tham chiếu mềm :: Nó ít nhiều giống như tham chiếu yếu. Nhưng bạn có thể nói rằng nó giữ đối tượng mạnh hơn một chút so với tham chiếu yếu từ bộ sưu tập rác.

Nếu người thu gom Rác thu thập tham chiếu yếu trong chính vòng đời đầu tiên, nó sẽ thu thập tham chiếu mềm trong chu kỳ thu gom Rác tiếp theo.

Tham chiếu mạnh :: Nó chỉ đối diện với hai loại tài liệu tham khảo ở trên. Họ ít thích thu gom rác (Hầu hết chúng không bao giờ được thu gom.)

Bạn có thể tham khảo liên kết sau để biết thêm thông tin:

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html


3
Tôi nghĩ điều này là sai - "Nếu người thu gom rác thu thập tài liệu tham khảo yếu trong chính vòng đời đầu tiên, nó sẽ thu thập tài liệu tham khảo mềm trong chu kỳ thu gom rác tiếp theo." Không nhất thiết phải như vậy, làm thế nào bạn có thể chắc chắn rằng chúng xảy ra trong lần chạy liên tiếp của GC? GC có thể cho phép các đối tượng tham chiếu mềm sống ngay cả trong lần chạy thứ 2 và lần thứ 3 cũng vậy. Không có tài liệu cho nó, nếu có thì xin vui lòng đề cập đến liên kết chỉ định.
Saurabh Patil

2
Ngoài ra, câu trả lời của bạn hơi mơ hồ, hãy nhìn vào câu này 'Nó ít nhiều giống như tham chiếu yếu. Nhưng bạn có thể nói rằng nó giữ đối tượng mạnh hơn một chút so với tham chiếu yếu từ bộ sưu tập rác. ' - anh ấy rõ ràng đang hỏi về sự khác biệt và không giống nhau, tất cả những từ này làm tăng thêm sự nhầm lẫn hơn là sự rõ ràng cho chủ đề.
Saurabh Patil

@SaurabhPatil - Bỏ lỡ bình luận của bạn. Đây là câu trả lời. 1. "anh ấy rõ ràng đang hỏi về sự khác biệt và không giống nhau" - Tham khảo mô tả của câu hỏi (không phải "chỉ" tiêu đề) "Xin vui lòng cho tôi một lời khuyên, và xin vui lòng cho tôi một số ví dụ để mô tả". 2. "Nhưng bạn có thể nói rằng nó giữ đối tượng nhiều hơn một chút ...." Tôi nghĩ SOF đưa ra một tùy chọn để bỏ phiếu và cũng đưa ra câu trả lời mới.
Sabya

14

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 có một tham chiếu mạnh đến một đối tượng, thì đối tượng đó không bao giờ có thể được thu thập / thu hồi bởi GC (Garbage Collector).

Nếu bạn chỉ có tài liệu tham khảo 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ớ.

Chúng tôi tạo các tham chiếu ảo đến một đối tượng để theo dõi khi nào đối tượng bị mê hoặc ReferenceQueue. Một khi bạn biết rằng bạn có thể thực hiện hoàn thiện hạt mịn. (Điều này sẽ cứu bạn khỏi việc vô tình hồi sinh đối tượng dưới dạng tham chiếu ảo không cung cấp cho bạn người giới thiệu). Tôi muốn đề nghị bạn đọc này bài viết để có được chiều sâu chi tiết về việc này.


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ể thoát khỏi 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ự

  • Người phục vụ - GC
  • Bạn - Đối tượng trong đống
  • Khu vực / không gian nhà hàng - Không gian heap
  • Khách hàng mới - Đối tượng mới muốn bàn trong nhà hàng

Bây giờ nếu bạn là một khách hàng mạnh mẽ (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


10

4 độ tham chiếu - Strong, Weak, Soft, Phantom

Mạnh - là một loại tham chiếu, làm cho đối tượng được tham chiếu không đủ điều kiện cho GC. lớp xây dựng. ví dụ: StringBuilder

Yếu - là một tài liệu tham khảo đủ điều kiện cho GC.

Mềm - là một loại tài liệu tham khảo có đối tượng đủ điều kiện cho GC cho đến khi bộ nhớ có sẵn. Tốt nhất cho bộ nhớ cache hình ảnh. Nó sẽ giữ chúng cho đến khi bộ nhớ có sẵn.

Phantom - là một loại tài liệu tham khảo có đối tượng đủ điều kiện trực tiếp cho GC. Chỉ được sử dụng để biết khi nào một đối tượng được xóa khỏi bộ nhớ.

sử dụng:

  1. Cho phép bạn xác định khi một đối tượng được xóa chính xác khỏi bộ nhớ.

  2. khi finalize()phương thức bị quá tải, thì GC có thể không xảy ra một cách kịp thời cho các đối tượng đủ điều kiện của hai lớp. Vì vậy, tham chiếu ảo làm cho chúng đủ điều kiện cho GC trước đó finalize(), là lý do tại sao bạn có thể nhận OutOfMemoryErrors ngay cả khi hầu hết các heap là rác.

Tham chiếu yếu là lý tưởng để thực hiện các mô-đun bộ đệm.


10

Tài liệu tham khảo mạnh mẽ

Đây là các tài liệu tham khảo đối tượng thường xuyên của bạn mà chúng tôi mã hàng ngày:

Employee emp = new Employee();

Biến số emp emp giữ một tham chiếu mạnh đến một đối tượng Nhân viên và các đối tượng có thể truy cập thông qua bất kỳ chuỗi tham chiếu mạnh nào không đủ điều kiện để thu gom rác. Thông thường, đây là những gì bạn muốn nhưng không phải luôn luôn. Bây giờ, giả sử chúng tôi đang tìm nạp rất nhiều nhân viên từ cơ sở dữ liệu trong bộ sưu tập hoặc bản đồ và chúng tôi cần xử lý chúng thường xuyên, vì vậy để giữ hiệu suất, chúng tôi sẽ giữ chúng trong bộ nhớ cache.

Theo như điều này là tốt nhưng bây giờ chúng tôi cần dữ liệu khác nhau và chúng tôi không cần những đối tượng Nhân viên đó và chúng không được tham chiếu từ bất cứ đâu ngoại trừ bộ đệm. Điều này gây ra rò rỉ bộ nhớ vì các đối tượng này không được sử dụng nhưng vẫn không đủ điều kiện cho bộ sưu tập rác và chúng tôi không thể xóa các đối tượng đó khỏi bộ đệm vì chúng tôi không có tham chiếu đến chúng? Vì vậy, ở đây, chúng ta cần làm trống toàn bộ bộ đệm một cách thủ công, điều này thật tẻ nhạt hoặc chúng ta có thể sử dụng các loại tham chiếu khác, ví dụ như Tài liệu tham khảo yếu.

Tài liệu tham khảo yếu

Một tham chiếu yếu không ghim một đối tượng vào bộ nhớ và sẽ là GC'd trong chu trình GC tiếp theo nếu không được tham chiếu từ các tham chiếu khác. Chúng ta có thể sử dụng lớp WeakReference do Java cung cấp để tạo ra loại bộ đệm bên trên, sẽ không lưu trữ các đối tượng không được tham chiếu từ nơi nào khác.

WeakReference<Cache> cache = new WeakReference<Cache>(data);

Để truy cập dữ liệu, bạn cần gọi cache.get (). Cuộc gọi để nhận này có thể trả về null nếu tham chiếu yếu là rác được thu thập: bạn phải kiểm tra giá trị được trả về để tránh NPE. Java cung cấp các bộ sưu tập sử dụng các tham chiếu yếu, ví dụ, lớp WeakHashMap lưu trữ các khóa (không phải giá trị) làm các tham chiếu yếu. Nếu khóa là GC'd thì giá trị cũng sẽ tự động bị xóa khỏi bản đồ.

Vì các tham chiếu yếu cũng là các đối tượng, chúng tôi cần một cách để dọn sạch chúng (chúng không còn hữu ích khi đối tượng mà chúng tham chiếu đã là GC'd). Nếu bạn chuyển ReferenceQueue vào hàm tạo cho tham chiếu yếu thì trình thu gom rác sẽ nối thêm tham chiếu yếu đó vào ReferenceQueue trước khi chúng được hoàn thành hoặc GC'd. Bạn có thể định kỳ xử lý hàng đợi này và đối phó với các tài liệu tham khảo đã chết.

Tài liệu tham khảo mềm

SoftReference giống như WeakReference nhưng ít có khả năng là rác được thu thập. Tài liệu tham khảo mềm được xóa theo quyết định của người thu gom rác theo nhu cầu bộ nhớ. Máy ảo đảm bảo rằng tất cả các tham chiếu mềm đến các đối tượng có thể tiếp cận mềm sẽ bị xóa trước khi nó ném OutOfMemoryError.

Tài liệu tham khảo Phantom

Tham chiếu Phantom là yếu nhất trong tất cả các loại tham chiếu, việc gọi get trên chúng sẽ luôn trả về null. Một đối tượng được tham chiếu ảo sau khi nó được hoàn thành, nhưng trước khi bộ nhớ được phân bổ của nó được lấy lại, Trái ngược với các tham chiếu yếu được xử lý trước khi chúng được hoàn thiện hoặc các tham chiếu Phantom của GC hiếm khi được sử dụng.

Vậy chúng hữu ích như thế nào? Khi bạn xây dựng một tham chiếu ảo, bạn phải luôn vượt qua trong ReferenceQueue. Điều này chỉ ra rằng bạn có thể sử dụng một tham chiếu ảo để xem khi nào đối tượng của bạn là GC'd.

Này, vì vậy, nếu các tham chiếu yếu được xử lý khi chúng được xem là hoàn thiện nhưng chưa phải là GC, chúng ta có thể tạo một tham chiếu mạnh mới cho đối tượng trong khối hoàn thiện và ngăn không cho đối tượng bị GC. Đúng, bạn có thể nhưng có lẽ bạn không nên làm điều này. Để kiểm tra trường hợp này, chu trình GC sẽ xảy ra ít nhất hai lần cho mỗi đối tượng trừ khi đối tượng đó chỉ có thể truy cập được bằng tham chiếu ảo. Đây là lý do tại sao bạn có thể hết đống ngay cả khi bộ nhớ của bạn chứa nhiều rác. Tài liệu tham khảo Phantom có ​​thể ngăn chặn điều này.

Bạn có thể đọc thêm về bài viết của tôi Các loại tài liệu tham khảo trong Java (Mạnh, Mềm, Yếu, Phantom) .


bạn đã viết rằng các điều chỉnh yếu sẽ được xử lý trong chu kỳ tiếp theo nếu không được điều chỉnh từ các điều chỉnh khác ... nhưng không nên xảy ra điều tương tự với các điều chỉnh sao? nếu không thể truy cập stron Revence theo bất kỳ cách nào sau đó bị xóa ... thì nếu vậy thì sự khác biệt lại ở đâu ...? # bối rối
filemonchot

1
Nếu một đối tượng đang được giới thiệu từ giả sử s1 (mạnh) và s2 (mạnh), đối tượng sẽ không đủ điều kiện để thu gom rác cho đến khi cả s1 và s2 bị hủy đăng ký nhưng nếu đối tượng được chuyển từ s1 (yếu) và s2 ( mạnh) sau đó đối tượng sẽ đủ điều kiện để thu gom rác trong chu trình GC tiếp theo khi nó bị hủy đăng ký chỉ từ s2, vì s1 là tham chiếu yếu và nếu đối tượng không có bất kỳ tham chiếu nào khác ngoại trừ đối tượng yếu thì nó đủ điều kiện cho GC
Naresh Joshi
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.