When to use weak references in .Net?

I have not personally come across a situation where I’ve needed to use WeakReference type in .Net, but the popular belief seems to be that it should be used in caches. Dr Jon Harrop gave a very good case against the use of WeakReferences in caches in his answer to this question.

I’ve also often heard AS3 developers talk about using weak references to save on memory footprint but based on the conversations I’ve had it seems to add complexity without necessarily accomplishing the intended goal, and the runtime behaviour is rather unpredictable. So much so that many simply give up on it and instead manage the memory usage more carefully/optimize their code to be less memory intensive (or making the trade-off of more CPU-cycles and smaller memory footprint).

Dr Jon Harrop also pointed out in his answer that the .Net weak references are not soft, and there’s an aggressive collection of weak references at gen0. According to MSDN, long weak references gives you the potential to recreate an object, but the state of the object remains unpredictable.!

Given these characteristics, I can’t think of a situation where weak references would be useful, perhaps someone could enlighten me?

6

I’ve found legitimate practical applications of weak references in the following three real-world scenarios that actually happened to me personally:

Application 1: Event handlers

You’re an entrepreneur. Your company sells a spark lines control for WPF. Sales are great but support costs are killing you. Too many customers are complaining of CPU hogging and memory leaks when they scroll through screens full of spark lines. The problem is their app is creating new spark lines as they come into view but data binding is preventing the old ones from being garbage collected. What do you do?

Introduce a weak reference between the data binding and your control so that data binding alone will no longer prevent your control from being garbage collected. Then add a finalizer to your control that tears down the data binding when it gets collected.

Application 2: Mutable graphs

You’re the next John Carmack. You’ve invented an ingenius new graph-based representation of hierarchical subdivision surfaces that makes Tim Sweeney’s games look like a Nintendo Wii. Obviously I’m not going to tell you exactly how it works but it all centers on this mutable graph where the neighbors of a vertex can be found in a Dictionary<Vertex, SortedSet<Vertex>>. The graph’s topology keep changing as the player runs around. There’s only one problem: your data structure is shedding unreachable subgraphs as it runs and you need to remove them or you’ll leak memory. Luckily you’re a genius so you know there is a class of algorithms specifically designed to locate and collect unreachable subgraphs: garbage collectors! You read Richard Jones’ excellent monograph on the subject but it leaves you perplexed and concerned about your imminent deadline. What do you do?

Simply by replacing your Dictionary with a weak hash table you can piggyback the existing GC and have it automatically collect your unreachable subgraphs for you! Back to leafing through Ferrari adverts.

Application 3: Decorating trees

You’re hanging from the ceiling of a cyclindrical room at a keyboard. You’ve got 60 seconds to sift through some BIG DATA before someone finds you. You came prepared with a beautiful stream-based parser that relies upon the GC to collect fragments of AST after they’ve been analyzed. But you realise you need extra metadata on each AST Node and you need it fast. What do you do?

You could use a Dictionary<Node, Metadata> to associate metadata with each node but, unless you clear it out, the strong references from the dictionary to old AST nodes will keep them alive and leak memory. The solution is a weak hash table which keeps only weak references to keys and garbage collects key-value bindings when the key becomes unreachable. Then, as AST nodes become unreachable they are garbage collected and their key-value binding is removed from the dictionary leaving the corresponding metadata unreachable so it too gets collected. Then all you have to do after your main loop has terminated is slide up back through the air vent remembering to replace it just as the security guard comes in.

Note that in all three of these real-world applications that actually happened to me I wanted the GC to collect as aggressively as possible. That’s why these are legitimate applications. Everybody else is wrong.

5

Given these characteristics, I can’t think of a situation where weak references would be useful, perhaps someone could enlighten me?

Microsoft document Weak Event Patterns.

In applications, it is possible that handlers that are attached to event sources will not be destroyed in coordination with the listener object that attached the handler to the source. This situation can lead to memory leaks. Windows Presentation Foundation (WPF) introduces a design pattern that can be used to address this issue, by providing a dedicated manager class for particular events and implementing an interface on listeners for that event. This design pattern is known as the weak event pattern.

The weak event pattern is designed to solve this memory leak problem. The weak event pattern can be used whenever a listener needs to register for an event, but the listener does not explicitly know when to unregister. The weak event pattern can also be used whenever the object lifetime of the source exceeds the useful object lifetime of the listener. (In this case, useful is determined by you.) The weak event pattern allows the listener to register for and receive the event without affecting the object lifetime characteristics of the listener in any way. In effect, the implied reference from the source does not determine whether the listener is eligible for garbage collection. The reference is a weak reference, thus the naming of the weak event pattern and the related APIs. The listener can be garbage collected or otherwise destroyed, and the source can continue without retaining noncollectible handler references to a now destroyed object.

1

Let me put this out first and come back to it:

A WeakReference is useful when you want to keep tabs on an object, but you DO NOT want your observations to prevent that object from being collected

So let’s start from the beginning:

–apologies in advance for any unintentional offense, but I’m gonna back up to “Dick and Jane” level for a moment since one can never tell ones audience.

So when you’ve got an object X – let’s specify it as an instance of class Foo – it CANNOT live on it’s own (mostly true); In the same way that “No man is an island”, there are only a few ways that an object can promoted to Islandhood – although it’s called being a GC root in CLR speak. Being a GC Root, or having an established chain of connections/references to a GC root, is basically what determines whether or not Foo x = new Foo() gets garbage collected.

If you cannot walk your way back to some GC root either by heap or stack walking, you are effectively orphaned, and will likely be marked/collected next cycle.

At this point, let’s look at some horrible-contrived examples:

First, our Foo:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>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--);
}
}
</code>
<code>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--); } } </code>
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--);
    }
}

Fairly simple – it’s not thread safe, so don’t try that, but keeps a rough “reference count” of active instances and decrements when they are finalized.

Now let’s look at a FooConsumer:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>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");
}
}
</code>
<code>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"); } } </code>
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");
    }
}

So we’ve got an object that’s already a GC root of it’s own (well…to be specific, it’ll be rooted via a chain straight to the app domain running this application, but that’s another topic) that has two methods of latching on to a Foo instance – let’s test it out:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>// 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();
</code>
<code>// 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(); </code>
// 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();

Now, from the above, would you expect the object-that-was-once-referred-to by f to be “collectable”?

No, because there is another object now holding a reference to it – the Dictionary in that Singleton static instance.

Ok, let’s try the weak approach:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>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();
</code>
<code>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(); </code>
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();

Now, when we whack our reference to the-Foo-that-was-once-f, there are no more “hard” references to the object, so it is collectable – the WeakReference created by the weak listener won’t prevent that.

Good use cases:

  • Event handlers (Although read this first: Weak Events in C#)

  • You’ve got a situation where you would cause a “recursive reference” (i.e., object A refers to object B, which refers to object A, also referred to as a “Memory Leak”) (edit: derp, of course this isn’t true)

  • You want to “broadcast” something to a collection of objects, but you don’t want to be the thing keeping them alive; a List<WeakReference> can be maintained easily, and even pruned by removing where ref.Target == null

3

Like logical leaks which are really hard to track down while users just tend to notice that running your software for a long time tends to take more and more memory and get slower and slower until they restart? I don’t.

Consider what happens if, when the user requests to remove application resource above, Thing2 fails to properly handle such an event under:

  1. Pointers
  2. Strong References
  3. Weak References

… and under which one of these such a mistake would likely be caught during testing, and which one wouldn’t and would fly under the radar like a stealth fighter bug. Shared ownership is, more often than most, a nonsensical idea.

A very illustrative example of weak references used to good effect is the ConditionalWeakTable, which is used by the DLR (among other places) to attach additional “members” to objects.

You don’t want the table to keep the object alive. This concept simply could not work without weak references.

But it kind of seems to me that all the uses for weak references came long after they were added to the language, since weak references have been part of .NET since version 1.1. It just seems like something you’d want to add, so that the lack of deterministic destruction won’t back you into a corner as far as language features are concerned.

1

If you have cache layer implemented with C# it’s much better too put your data in cache as weak references, it could help to improve your cache layer performance.

Think that approach also could be applied to session implementation. Because session is long living object most of the time, it could be some case when you have no memory for new user. In that case it will be much better to delete some else user session object then throwing OutOfMemoryException.

Also, if you have a large object in your application (some big lookup table, etc), that should be used quite seldom and recreating of such an object isn’t a very expensive procedure. Then better have it like a week reference to have a way to free your memory when you really need that.

3

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật