[問題] 關於PhantomReference

看板java作者 (接下來如何?)時間4年前 (2020/07/12 14:54), 4年前編輯推噓3(3017)
留言20則, 2人參與, 4年前最新討論串1/1
小弟我最近在研究SoftReference、WeakReference、PhantomReference等功能 SoftReference、WeakReference很好理解, 沒什麼問題. 但我在研究PhantomReference時覺得我的code跟我對PhantomReference理解有點出入 以下是我測試的code, jvm 設定 -Xms5M -Xmx10M (有透過MBean確認過參數無誤) (01) private volatile boolean isRun = true; (02) (03) private void test() throws InterruptedException { (04) ReferenceQueue<byte[]> rq = new ReferenceQueue<>(); (05) (06) pollingReferenceQueue(rq); // fork thread poll referenceQueue (07) (08) try { (09) List<Object> l = new ArrayList<>(); (10) (11) int times = 20; (12) long restMs = 1000; (13) for (int i = 1; i <= times; i++) { (14) byte[] buff = new byte[1024 * 1024]; (15) PhantomReference<byte[]> pr = new PhantomReference<>(buff, rq); (16) l.add(pr); // 這邊打開讓pr被強引用, rq才會收到資料?? (17) (18) System.gc(); (19) (20) System.out.println("<main> " + "(" + i + ") " + pr); (21) (22) Thread.sleep(restMs); (23) } (24) (25) } finally { (26) isRun = false; (27) } (28) } (29) (30) private void pollingReferenceQueue(ReferenceQueue<byte[]> rq) { (31) new Thread(() -> { (32) while (this.isRun) { (33) Reference<? extends byte[]> v = rq.poll(); (34) (35) if (v == null) { (36) System.out.println("<poll> " + null); (37) } else { (38) System.out.println("<poll> recycle " + v.toString()); (39) } (40) (41) try { (42) Thread.sleep(100); (43) } catch (InterruptedException e) { (44) e.printStackTrace(); (45) } (46) } (47) }, "polling").start(); (48) } 我的問題在第16行, 當沒有把pr給強引用的時候, 當要被GC的時候並不會丟到rq裡? 但當pr給強引用的時候, 要被回收時就會出現在rq裡? 我對ReferenceQueue的理解是 "當Reference所參照的物件準備要回收的時候, 其Reference會先放置ReferenceQueue" "因此可以利用ReferenceQueue得知有某些物件沒有人使用準備要被回收了!" 所以我不能理解的是為什麼pr被強引用之後準備回收才會被丟到rq裡? 但pr沒有被強引用要被回收時卻沒有丟到rq裡? (因為沒有OOM) 不曉得有沒有大大能解惑, 是我理解錯誤還是我的code在使用上就錯了? -- 你只是大大的世界中小小的一個島嶼 在你懷中長大的我們 從未忘記 我要用全部的力氣唱出對你的深情 歌聲中 只是真心的讚美 929 吳志寧 也有感謝和依戀 疼惜和憂煩 全心全意愛你 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 110.26.10.55 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/java/M.1594536845.A.512.html ※ 編輯: NullLife (110.26.10.55 臺灣), 07/12/2020 14:55:54 ※ 編輯: NullLife (110.26.10.55 臺灣), 07/12/2020 15:01:34

07/13 09:22, 4年前 , 1F
pr在迴圈內,每繞一次就生命週期結束,list救了它.把pr移出
07/13 09:22, 1F

07/13 09:22, 4年前 , 2F
迴圈再試看看
07/13 09:22, 2F

07/13 11:23, 4年前 , 3F
我看文件上面寫的,
07/13 11:23, 3F

07/13 11:23, 4年前 , 4F
感覺跟這個有關
07/13 11:23, 4F

07/13 11:30, 4年前 , 5F
https://bit.ly/3foeCVf 提供一下文件連結
07/13 11:30, 5F
啊啊啊 看起來就是它耶!! 原來doc就有描述了QQ 感謝大大 ※ 編輯: NullLife (125.227.32.37 臺灣), 07/16/2020 18:57:30

07/16 19:52, 4年前 , 6F
今天發現我第一行寫的不夠清楚,應該是把pr的宣告移出迴圈
07/16 19:52, 6F

07/16 19:52, 4年前 , 7F
,看到原po有回覆才發現當初寫得太過簡略 XD
07/16 19:52, 7F

07/16 20:22, 4年前 , 8F
B大的答案我有試過,看起來還是一樣,看來就像文件所說
07/16 20:22, 8F

07/16 20:22, 4年前 , 9F
只要pr變成unreachable,就不會被加入到q
07/16 20:22, 9F

07/16 20:22, 4年前 , 10F
ueue中
07/16 20:22, 10F

07/17 09:30, 4年前 , 11F
感覺是如果不用list來記錄每次new的PhantomReference,只
07/17 09:30, 11F

07/17 09:30, 4年前 , 12F
會記錄到最後一次的new PhantomReference(.),而那次迴圈
07/17 09:30, 12F

07/17 09:31, 4年前 , 13F
會結束,list l 和pr的生命週期也結束,而gc只是標誌將執行
07/17 09:31, 13F

07/17 09:31, 4年前 , 14F
並非呼叫當下立即執行,因此最後一次gc實際執行時,最後一
07/17 09:31, 14F

07/17 09:32, 4年前 , 15F
次的new PhantomReference也unreachable了.所以l的效果是
07/17 09:32, 15F

07/17 09:33, 4年前 , 16F
讓前面幾次的gc來得及回報前幾次的pr. 要確保gc實際執行
07/17 09:33, 16F

07/17 09:34, 4年前 , 17F
時pr還活著,光移出迴圈還不夠,可能要變field,而且應該用
07/17 09:34, 17F

07/17 09:34, 4年前 , 18F
array或list,以記錄每次的new PhantomReference(.)
07/17 09:34, 18F

07/17 16:00, 4年前 , 19F
我的看法大致跟B大一樣,重點就是確保pr在GC時還可
07/17 16:00, 19F

07/17 16:00, 4年前 , 20F
以被reach到就可以了
07/17 16:00, 20F
文章代碼(AID): #1V2hEDKI (java)
文章代碼(AID): #1V2hEDKI (java)