作者NullLife (接下来如何?)
看板java
标题[问题] 关於PhantomReference
时间Sun Jul 12 14:54:02 2020
小弟我最近在研究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://webptt.com/cn.aspx?n=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
1F:→ bitlife: pr在回圈内,每绕一次就生命周期结束,list救了它.把pr移出 07/13 09:22
2F:→ bitlife: 回圈再试看看 07/13 09:22
4F:→ tw11509: 感觉跟这个有关 07/13 11:23
啊啊啊 看起来就是它耶!! 原来doc就有描述了QQ 感谢大大
※ 编辑: NullLife (125.227.32.37 台湾), 07/16/2020 18:57:30
6F:→ bitlife: 今天发现我第一行写的不够清楚,应该是把pr的宣告移出回圈 07/16 19:52
7F:→ bitlife: ,看到原po有回覆才发现当初写得太过简略 XD 07/16 19:52
8F:推 tw11509: B大的答案我有试过,看起来还是一样,看来就像文件所说 07/16 20:22
9F:→ tw11509: 只要pr变成unreachable,就不会被加入到q 07/16 20:22
10F:→ tw11509: ueue中 07/16 20:22
11F:→ bitlife: 感觉是如果不用list来记录每次new的PhantomReference,只 07/17 09:30
12F:→ bitlife: 会记录到最後一次的new PhantomReference(.),而那次回圈 07/17 09:30
13F:→ bitlife: 会结束,list l 和pr的生命周期也结束,而gc只是标志将执行 07/17 09:31
14F:→ bitlife: 并非呼叫当下立即执行,因此最後一次gc实际执行时,最後一 07/17 09:31
15F:→ bitlife: 次的new PhantomReference也unreachable了.所以l的效果是 07/17 09:32
16F:→ bitlife: 让前面几次的gc来得及回报前几次的pr. 要确保gc实际执行 07/17 09:33
17F:→ bitlife: 时pr还活着,光移出回圈还不够,可能要变field,而且应该用 07/17 09:34
18F:→ bitlife: array或list,以记录每次的new PhantomReference(.) 07/17 09:34
19F:推 tw11509: 我的看法大致跟B大一样,重点就是确保pr在GC时还可 07/17 16:00
20F:→ tw11509: 以被reach到就可以了 07/17 16:00