弱引用

在計算機程式設計中，弱引用與強引用相對，是指不能確保其引用的物件不會被垃圾回收器回收的引用。一個物件若只被弱引用所引用，則被認為是不可訪問（或弱可訪問）的，並因此可能在任何時刻被回收。一些配有垃圾回收機制的語言，如 Java、C#、Python、Perl、Lisp 等都在不同程度上支援弱引用。

垃圾回收

垃圾回收用來清理不會再使用的物件，從而降低記憶體洩露和資料損壞的可能性。垃圾回收主要有兩種型別：追蹤和引用計數。引用計數會記錄給定物件的引用個數，並在引用個數為零時收集該物件。由於一次僅能有一個物件被回收，引用計數無法回收迴圈引用的物件。一組相互引用的物件若沒有被其它物件直接引用，並且不可訪問，則會永久存活下來。一個應用程式如果持續地產生這種不可訪問的物件群組，就會發生記憶體洩漏。在物件群組內部使用弱引用（即不會在引用計數中被計數的引用）有時能避免出現引用環，因此弱引用可用於解決迴圈引用的問題。如 Apple 的 Cocoa 框架就推薦使用這種方法，具體為，在父對子引用時使用強引用，子對父引用時使用弱引用，從而避免了迴圈引用。

程式對一些物件只進行弱引用，透過此法可以指明哪些物件是不重要的，因此弱引用也用於儘量減少記憶體中不必要的物件存在的數量。

變種

有些語言包含多種強度的弱引用。例如 Java，在 java.lang.ref 包中定義了軟引用、弱引用和虛引用，引用強度依次遞減。每種引用都有相對應的 可訪問性概念。垃圾回收器（GC）透過判斷物件的可訪問性型別來確定何時回收該物件。當一個物件是軟可訪問的，垃圾回收器就可以安全回收這個物件，但如果垃圾回收器認為 JVM 還能空出可用記憶體（比如 JVM 還有大量未使用的堆空間），則有可能不會立刻回收軟可訪問的物件。但對於弱可訪問的物件，一旦被垃圾回收器注意到，就會被回收。和其他引用種類不同，虛引用無法跟蹤。但另一方面，虛引用提供了一種機制，當一個物件被回收時程式可以得到通知（實現於 ReferenceQueues）。

一些未配有垃圾回收機制的語言，比如 C++，也提供強 / 弱引用的功能，以作為對垃圾回收庫的支援。在 C++ 中，普通指標可看做弱引用，智慧指標可看做強引用，儘管指標不能算 "真正" 的弱引用，因為弱引用應該能知道何時物件變成不可訪問的了。

示例

弱引用可用於在應用程式中維護一個當前被引用的物件的列表。該列表必須弱引用到那些物件，否則一旦物件被新增到列表中，由於它們被列表引用了，在程式執行期間將永遠不會被回收。

3.1 Java

Java 是第一個將強引用作為預設物件引用的主流語言。之前的（ANSI）C 語言只支援弱引用。而後 David Hostettler Wain 和 Scott Alexander Nesmith 注意到事件樹無法正常釋放的問題，結果在大約 1998 年，推出了分別會被計數和不會被計數的強、弱引用。

如果建立了一個弱引用，然後在程式碼的其它地方用 get 獲得真實物件，由於弱引用無法阻止垃圾回收，get 隨時有可能開始返回 null（假如物件沒有被強引用）。

import java.lang.ref.WeakReference;

public class ReferenceTest {public static void main (String args) throws InterruptedException {WeakReference r = new WeakReference (new String ("I'm here"));

WeakReference sr = new WeakReference ("I'm here");

System.out.println ("before gc: r=" + r.get + ", static=" + sr.get );

System.gc ;

Thread.sleep (100);

// 只有 r.get 變為 null

System.out.println ("after gc: r=" + r.get + ", static=" + sr.get );

	}

}

弱引用還可以用來實現快取。例如用弱雜湊表，即透過弱引用來快取各種引用物件的雜湊表。當垃圾回收器執行時，假如應用程式的記憶體佔用量高到一定程度，那些不再被其它物件所引用的快取物件就會被自動釋放。

3.2 Smalltalk

s1 := 'hello' copy. "這是個強引用"

s2 := 'world' copy. "這是個強引用"

a := WeakArray with:s1 with:s2.

a printOn: Transcript.

ObjectMemory collectGarbage.

a printOn: Transcript. "兩個元素都還在"

s1 := nil. "移除強引用"

ObjectMemory collectGarbage.

a printOn: Transcript. "第一個元素消失"

s2 := nil. "移除強引用"

ObjectMemory collectGarbage.

a printOn: Transcript. "第二個元素消失"

3.3 Lua

weaktable = setmetatable (, {_mode="v"})

weak_table.item =

print (weak_table.item)

collectgarbage

print (weak_table.item)

3.4 Objective-C 2.0

在 Objective-C 2.0 中，除了垃圾回收，自動引用計數也會受弱引用的影響。下面這個例子中的所有變數和屬性都是弱引用。

@interface WeakRef : NSObject

{

weak NSString *str1;

assign NSString *str2;

}

@property (nonatomic, weak) NSString *str3;

@property (nonatomic, assign) NSString *str4;

@end

weak (weak) 和 assign (assign) 的區別在於，當變數指向的物件被重新分配時，變數的值是否會跟著改變。weak 宣告的變數會變為 nil，而 assign 宣告的變數則會保持不變，成為一個懸擺指標。從 Mac OX 10.7 “獅子” 系統和 iOS 5 開始，隨著 Xcode 4.1 版本的推出，weak 引用被引入到 Objective-C 語言中（4.2 版本開始支援 iOS）。老版本的 Mac OS X、iOS 和 GNUstep 僅支援用 assign 宣告弱引用。

3.5 Vala

class Node {

public weak Node prev; // 弱引用可避免列表中的節點之間出現迴圈引用

public Node next;

}

3.6 Python

>>> import weakref

>>> import gc

>>> class Egg:

... def spam (self):

... print ("I'm alive!")

...

>>> obj = Egg >>> weak_obj = weakref.ref (obj)

>>> weak_obj .spam

I'm alive!

>>> obj = "Something else"

>>> gc.collect

35

>>> weak_obj .spam

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'NoneType' object has no attribute'spam'