Java Reference概念整理

本文深入解析Java中的四种引用类型:强引用、弱引用、软引用和幻影引用的工作原理及应用场景,包括如何利用这些引用类型进行高效内存管理和垃圾回收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Strong Reference, 强引用,即Java标准的引用方式,表示GC从 Root Set 开始向下扫描,可以找到对应的 Strong Reference。

Referent,被包装为 Weak, Soft, Phantom Reference的对象引用称之为 referent。后面的内容会多次提到这个名词。

Weak Reference, 弱引用。当一个referent,在运行时没有同时被强,软引用,只被Weak Reference自身引用,且Weak Reference从 Root Set 可达,则该referent会被GC回收。

WR的作用,一般是为referent提供一个被回收的凭据,结合ReferenceQueue可以让程序在第一时间得到referent被回收的事件,从而做一些额外的clean操作。(如果对ReferenceQueue作用和回调感兴趣,可以先看最下面的 ReferenceQueue 简介)

Soft Reference, 软引用。它是除strong外,生命周期最长的一种 Reference,只有当JVM Heap中充满Strong References, Full GC无法为heap腾出更多空间而即将抛出OOM时,SoftReferences会被GC回收。

SR的作用一般是用作不限大小的 cache(无需remove)。
比如将其 Soft Reference 无限地放入 hashmap 中,而不关心hashmap内的对象数量是否会撑爆heap,也不需要手动 remove。
当Heap容量达到OOM触发条件时,VM会自动回收该map里的所有SoftReferences.

Phanton Reference, 是一种特殊的Reference,正如他的名字所表达的,幻影引用,他可以像幻影一样附着在referent上。
当GC在遍历引用关系时,如果发现被phantom reference包装过的referent不存在strong, weak, soft引用时(就是除phantom外没有任何引用,幻影的由来),GC会将 phantom reference 放入 Reference queue。以便程序在另一边通过queue的remove/poll方法,感知referent被GC回收的事件。(如果对ReferenceQueue作用和回调感兴趣,可以先看最下面 ReferenceQueue 简介)

另外,我们知道,GC在回收对象前会先调用对象自身的finalize()方法,如果它有实现的话,然后再清掉内存。而Phantom Reference的回调(enqueue)是在对象的finalize后,回收前触发。这跟 WeakReference不一样。WR是在回收后才通知的。在这个特殊的阶段可以做一些特殊的clean操作。

为什么 Phantom Reference 的get总是返回null?
因为phantom reference想做到幻影(除自身外,不跟其他任何引用有关联),所以不允许程序能通过自身的get方法得到referent,而破坏幻影的初衷。

实例代码

  1. <span style=“color:#7f0055; font-weight:bold”>package</span> <span style=“color:#000000”>com.kenwublog.reference</span><span style=“color:#000000”>;</span>  
  2.    
  3. <span style=”color:#7f0055; font-weight:bold”>import</span> <span style=“color:#000000”>java.lang.ref.PhantomReference</span><span style=“color:#000000”>;</span>  
  4. <span style=”color:#7f0055; font-weight:bold”>import</span> <span style=“color:#000000”>java.lang.ref.Reference</span><span style=“color:#000000”>;</span>  
  5. <span style=”color:#7f0055; font-weight:bold”>import</span> <span style=“color:#000000”>java.lang.ref.ReferenceQueue</span><span style=“color:#000000”>;</span>  
  6. <span style=”color:#7f0055; font-weight:bold”>import</span> <span style=“color:#000000”>java.util.HashMap</span><span style=“color:#000000”>;</span>  
  7.    
  8. <span style=”color:#7f0055; font-weight:bold”>public</span> <span style=“color:#7f0055; font-weight:bold”>class</span> PhantomReferenceTest <span style=“color:#000000”>{</span>  
  9.    
  10.     <span style=”color:#7f0055; font-weight:bold”>public</span> <span style=“color:#7f0055; font-weight:bold”>static</span> <span style=“color:#7f0055; font-weight:bold”>void</span> main<span style=“color:#000000”>(</span><span style=“color:#000000”>String</span><span style=“color:#000000”>[</span><span style=“color:#000000”>]</span> args<span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  11.         <span style=”color:#000000”>ReferenceQueue</span> referenceQueue <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>ReferenceQueue</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  12.         <span style=”color:#000000”>Object</span> object <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>Object</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  13.             <span style=”color:#7f0055; font-weight:bold”>public</span> <span style=“color:#000000”>String</span> toString<span style=“color:#000000”>(</span><span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  14.                 <span style=”color:#7f0055; font-weight:bold”>return</span> <span style=“color:#0000ff”>“Referenced Object”</span><span style=“color:#000000”>;</span>  
  15.             <span style=”color:#000000”>}</span>  
  16.         <span style=”color:#000000”>}</span><span style=“color:#000000”>;</span>  
  17.    
  18.         <span style=”color:#000000”>Object</span> data <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>Object</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  19.             <span style=”color:#7f0055; font-weight:bold”>public</span> <span style=“color:#000000”>String</span> toString<span style=“color:#000000”>(</span><span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  20.                 <span style=”color:#7f0055; font-weight:bold”>return</span> <span style=“color:#0000ff”>“Data”</span><span style=“color:#000000”>;</span>  
  21.             <span style=”color:#000000”>}</span>  
  22.         <span style=”color:#000000”>}</span><span style=“color:#000000”>;</span>  
  23.    
  24.         <span style=”color:#000000”>HashMap</span> map <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>HashMap</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  25.         <span style=”color:#000000”>Reference</span> reference <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>null</span><span style=“color:#000000”>;</span>  
  26.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span><span style=“color:#0000ff”>“Testing PhantomReference.”</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  27.         reference <span style=”color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>PhantomReference</span><span style=“color:#000000”>(</span>object, referenceQueue<span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  28.    
  29.         map.<span style=”color:#000000”>put</span><span style=“color:#000000”>(</span>reference, data<span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  30.    
  31.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>reference.<span style=“color:#000000”>get</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// null</span>  
  32.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>map.<span style=“color:#000000”>get</span><span style=“color:#000000”>(</span>reference<span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// Data</span>  
  33.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>reference.<span style=“color:#000000”>isEnqueued</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// false</span>  
  34.    
  35.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>gc</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  36.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>reference.<span style=“color:#000000”>get</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// null</span>  
  37.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>map.<span style=“color:#000000”>get</span><span style=“color:#000000”>(</span>reference<span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// Data</span>  
  38.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>reference.<span style=“color:#000000”>isEnqueued</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// false</span>  
  39.    
  40.         object <span style=”color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>null</span><span style=“color:#000000”>;</span>  
  41.         data <span style=”color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>null</span><span style=“color:#000000”>;</span>  
  42.    
  43.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>gc</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  44.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>reference.<span style=“color:#000000”>get</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// null</span>  
  45.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>map.<span style=“color:#000000”>get</span><span style=“color:#000000”>(</span>reference<span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// Data</span>  
  46.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>reference.<span style=“color:#000000”>isEnqueued</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// true, because object has been reclaimed.</span>  
  47.     <span style=”color:#000000”>}</span>  
  48.    
  49. <span style=”color:#000000”>}</span>  
package com.kenwublog.reference;
 
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
 
public class PhantomReferenceTest {
 
    public static void main(String[] args) {
        ReferenceQueue referenceQueue = new ReferenceQueue();
        Object object = new Object() {
            public String toString() {
                return "Referenced Object";
            }
        };
 
        Object data = new Object() {
            public String toString() {
                return "Data";
            }
        };
 
        HashMap map = new HashMap();
        Reference reference = null;
        System.out.println("Testing PhantomReference.");
        reference = new PhantomReference(object, referenceQueue);
 
        map.put(reference, data);
 
        System.out.println(reference.get()); // null
        System.out.println(map.get(reference)); // Data
        System.out.println(reference.isEnqueued()); // false
 
        System.gc();
        System.out.println(reference.get()); // null
        System.out.println(map.get(reference)); // Data
        System.out.println(reference.isEnqueued()); // false
 
        object = null;
        data = null;
 
        System.gc();
        System.out.println(reference.get()); // null
        System.out.println(map.get(reference)); // Data
        System.out.println(reference.isEnqueued()); // true, because object has been reclaimed.
    }
 
}

ReferenceQueue,一种当 weak, soft, phantom的referent被GC回收后,提供事件回调的接口。需要在实例化三大reference时,通过构造函数传入,phantom reference是强制需要传入的,weak和soft可不传。

回调过程:

GC回收referent后(phantom是在回收前,finalize后),将reference enqueue到RQ中,程序通过调用RQ的remove方法来感知reference被GC回收的事件。
remove方法是阻塞的,当没有referent被回收时(GC未调用enqueue),remove方法会一直挂起线程,当有referent被回收时,该方法返回 referent对应的reference对象。
同样,RQ也提供了一个非阻塞的方法 poll,但这样就做不到实时回调了。

实例

  1. <span style=“color:#7f0055; font-weight:bold”>package</span> <span style=“color:#000000”>com.kenwublog.reference</span><span style=“color:#000000”>;</span>  
  2.    
  3. <span style=”color:#7f0055; font-weight:bold”>import</span> <span style=“color:#000000”>java.lang.ref.Reference</span><span style=“color:#000000”>;</span>  
  4. <span style=”color:#7f0055; font-weight:bold”>import</span> <span style=“color:#000000”>java.lang.ref.ReferenceQueue</span><span style=“color:#000000”>;</span>  
  5. <span style=”color:#7f0055; font-weight:bold”>import</span> <span style=“color:#000000”>java.lang.ref.WeakReference</span><span style=“color:#000000”>;</span>  
  6. <span style=”color:#7f0055; font-weight:bold”>import</span> <span style=“color:#000000”>java.util.HashMap</span><span style=“color:#000000”>;</span>  
  7.    
  8. <span style=”color:#7f0055; font-weight:bold”>public</span> <span style=“color:#7f0055; font-weight:bold”>class</span> ReferenceQueueTest <span style=“color:#000000”>{</span>  
  9.    
  10.     <span style=”color:#7f0055; font-weight:bold”>public</span> <span style=“color:#7f0055; font-weight:bold”>static</span> <span style=“color:#7f0055; font-weight:bold”>void</span> main<span style=“color:#000000”>(</span><span style=“color:#000000”>String</span><span style=“color:#000000”>[</span><span style=“color:#000000”>]</span> args<span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  11.         <span style=”color:#7f0055; font-weight:bold”>final</span> <span style=“color:#000000”>ReferenceQueue</span> q <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>ReferenceQueue</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  12.         <span style=”color:#000000”>String</span> str <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>String</span><span style=“color:#000000”>(</span><span style=“color:#0000ff”>“AK47”</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  13.         <span style=”color:#000000”>WeakReference</span> wr <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>WeakReference</span><span style=“color:#000000”>(</span>str, q<span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  14.    
  15.         <span style=”color:#000000”>Thread</span> t <span style=“color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>new</span> <span style=“color:#000000”>Thread</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>{</span>  
  16.             @Override  
  17.             <span style=”color:#7f0055; font-weight:bold”>public</span> <span style=“color:#7f0055; font-weight:bold”>void</span> run<span style=“color:#000000”>(</span><span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  18.                 <span style=”color:#7f0055; font-weight:bold”>try</span> <span style=“color:#000000”>{</span>  
  19.                     <span style=”color:#000000”>Reference</span> reference <span style=“color:#000000”>=</span> q.<span style=“color:#000000”>remove</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  20.                     <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span>reference <span style=“color:#000000”>+</span> <span style=“color:#0000ff”>“ event fired.”</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  21.                 <span style=”color:#000000”>}</span> <span style=“color:#7f0055; font-weight:bold”>catch</span> <span style=“color:#000000”>(</span><span style=“color:#000000”>InterruptedException</span> e<span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  22.                     e.<span style=”color:#000000”>printStackTrace</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  23.                 <span style=”color:#000000”>}</span>  
  24.             <span style=”color:#000000”>}</span>  
  25.         <span style=”color:#000000”>}</span><span style=“color:#000000”>;</span>  
  26.         t.<span style=”color:#000000”>setDaemon</span><span style=“color:#000000”>(</span><span style=“color:#7f0055; font-weight:bold”>true</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  27.         t.<span style=”color:#000000”>start</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  28.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span><span style=“color:#0000ff”>“Reference Queue is listening.”</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  29.    
  30.         str <span style=”color:#000000”>=</span> <span style=“color:#7f0055; font-weight:bold”>null</span><span style=“color:#000000”>;</span> <span style=“color:#008200; font-style:italic”>// clear strong reference</span>  
  31.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span><span style=“color:#0000ff”>“Ready to gc”</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  32.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>gc</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  33.         <span style=”color:#7f0055; font-weight:bold”>try</span> <span style=“color:#000000”>{</span>  
  34.             <span style=”color:#000000”>Thread</span>.<span style=“color:#000000”>sleep</span><span style=“color:#000000”>(</span><span style=“color:#000000”>2000</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  35.         <span style=”color:#000000”>}</span> <span style=“color:#7f0055; font-weight:bold”>catch</span> <span style=“color:#000000”>(</span><span style=“color:#000000”>InterruptedException</span> e<span style=“color:#000000”>)</span> <span style=“color:#000000”>{</span>  
  36.             e.<span style=”color:#000000”>printStackTrace</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  37.         <span style=”color:#000000”>}</span>  
  38.         <span style=”color:#000000”>System</span>.<span style=“color:#000000”>out</span>.<span style=“color:#000000”>println</span><span style=“color:#000000”>(</span><span style=“color:#0000ff”>“wr.get: ”</span> <span style=“color:#000000”>+</span> wr.<span style=“color:#000000”>get</span><span style=“color:#000000”>(</span><span style=“color:#000000”>)</span><span style=“color:#000000”>)</span><span style=“color:#000000”>;</span>  
  39.     <span style=”color:#000000”>}</span>  
  40.    
  41. <span style=”color:#000000”>}</span>  
package com.kenwublog.reference;
 
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
 
public class ReferenceQueueTest {
 
    public static void main(String[] args) {
        final ReferenceQueue q = new ReferenceQueue();
        String str = new String("AK47");
        WeakReference wr = new WeakReference(str, q);
 
        Thread t = new Thread(){
            @Override
            public void run() {
                try {
                    Reference reference = q.remove();
                    System.out.println(reference + " event fired.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t.setDaemon(true);
        t.start();
        System.out.println("Reference Queue is listening.");
 
        str = null; // clear strong reference
        System.out.println("Ready to gc");
        System.gc();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("wr.get: " + wr.get());
    }
 
}

参考资料

http://mindprod.com/jgloss/phantom.html (References的目的,在GC的哪种阶段触发对比表格)
http://www.pawlan.com/monica/articles/refobjs/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值