Hãy để tôi đưa nó ra trước và quay lại với nó:
WeakReference rất hữu ích khi bạn muốn giữ các tab trên một đối tượng, nhưng bạn KHÔNG muốn các quan sát của mình ngăn chặn đối tượng đó được thu thập
Vì vậy, hãy bắt đầu lại từ đầu:
--apology trước cho bất kỳ hành vi phạm tội vô ý, nhưng tôi sẽ trở lại mức "Dick và Jane" trong một khoảnh khắc vì người ta không bao giờ có thể nói với khán giả.
Vì vậy, khi bạn đã có một đối tượng X
- hãy xác định nó là một ví dụ của class Foo
- nó KHÔNG THỂ tự sống (chủ yếu là sự thật); Theo cùng một cách "Không có ai là một hòn đảo", chỉ có một vài cách mà một đối tượng có thể thăng cấp lên Đảo - mặc dù nó được gọi là gốc GC trong CLR. Là một gốc Root, hoặc có một chuỗi các kết nối / tham chiếu được thiết lập đến gốc GC, về cơ bản là điều quyết định việc Foo x = new Foo()
có thu gom rác hay không .
Nếu bạn không thể đi bộ trở lại một số gốc GC bằng cách đi bộ hoặc chồng, bạn sẽ mồ côi một cách hiệu quả, và có khả năng sẽ được đánh dấu / thu thập chu kỳ tiếp theo.
Tại thời điểm này, chúng ta hãy xem xét một số ví dụ kinh khủng:
Đầu tiên, chúng tôi Foo
:
public class Foo
{
private static volatile int _ref = 0;
public event EventHandler FooEvent;
public Foo()
{
_ref++;
Console.WriteLine("I am #{0}", _ref);
}
~Foo()
{
Console.WriteLine("#{0} dying!", _ref--);
}
}
Khá đơn giản - nó không an toàn cho chủ đề, vì vậy đừng thử điều đó, nhưng vẫn giữ một "số tham chiếu" sơ bộ của các trường hợp hoạt động và giảm dần khi chúng được hoàn thành.
Bây giờ hãy xem xét một FooConsumer
:
public class NastySingleton
{
// Static member status is one way to "get promoted" to a GC root...
private static NastySingleton _instance = new NastySingleton();
public static NastySingleton Instance { get { return _instance;} }
// testing out "Hard references"
private Dictionary<Foo, int> _counter = new Dictionary<Foo,int>();
// testing out "Weak references"
private Dictionary<WeakReference, int> _weakCounter = new Dictionary<WeakReference,int>();
// Creates a strong link to Foo instance
public void ListenToThisFoo(Foo foo)
{
_counter[foo] = 0;
foo.FooEvent += (o, e) => _counter[foo]++;
}
// Creates a weak link to Foo instance
public void ListenToThisFooWeakly(Foo foo)
{
WeakReference fooRef = new WeakReference(foo);
_weakCounter[fooRef] = 0;
foo.FooEvent += (o, e) => _weakCounter[fooRef]++;
}
private void HandleEvent(object sender, EventArgs args, Foo originalfoo)
{
Console.WriteLine("Derp");
}
}
Vì vậy, chúng ta đã có một đối tượng đã là gốc GC của chính nó (cụ thể là ... cụ thể, nó sẽ được bắt nguồn từ một chuỗi thẳng đến miền ứng dụng chạy ứng dụng này, nhưng đó là một chủ đề khác) có hai phương thức về việc chốt một Foo
ví dụ - hãy kiểm tra nó:
// Our foo
var f = new Foo();
// Create a "hard reference"
NastySingleton.Instance.ListenToThisFoo(f);
// Ok, we're done with this foo
f = null;
// Force collection of all orphaned objects
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Bây giờ, từ những điều trên, bạn có mong muốn đối tượng đã từng được nhắc f
đến là "có thể sưu tập" không?
Không, bởi vì có một đối tượng khác hiện đang giữ một tham chiếu đến nó - Dictionary
trong Singleton
trường hợp tĩnh đó .
Ok, chúng ta hãy thử cách tiếp cận yếu:
f = new Foo();
NastySingleton.Instance.ListenToThisFooWeakly(f);
// Ok, we're done with this foo
f = null;
// Force collection of all orphaned objects
// This should collect # 2 - you'll see a "#2 dying"
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Bây giờ, khi chúng tôi đưa tài liệu tham khảo của chúng tôi vào Foo
- đó là một lần- f
, không có tài liệu tham khảo "cứng" nào nữa cho đối tượng, vì vậy nó có thể được thu thập - WeakReference
do người nghe yếu tạo ra sẽ không ngăn chặn điều đó.
Các trường hợp sử dụng tốt:
Trình xử lý sự kiện (Mặc dù đọc phần này trước: Sự kiện yếu trong C # )
Bạn đã có một tình huống trong đó bạn sẽ gây ra một "tham chiếu đệ quy" (nghĩa là đối tượng A đề cập đến đối tượng B, đề cập đến đối tượng A, còn được gọi là "Rò rỉ bộ nhớ") (chỉnh sửa: derp, tất nhiên đây không phải là 'đúng)
Bạn muốn "phát" một cái gì đó đến một bộ sưu tập các đối tượng, nhưng bạn không muốn là thứ giữ cho chúng tồn tại; một List<WeakReference>
có thể được duy trì dễ dàng, và thậm chí cắt tỉa bằng cách loại bỏ nơiref.Target == null