Are C# weak references in fact soft?
Asked Answered
G

3

19

The basic difference is that weak references are supposed to be claimed on each run of the GC (keep memory footprint low) while soft references ought to be kept in memory until the GC actually requires memory (they try to expand lifetime but may fail anytime, which is useful for e.g. caches especially of rather expensive objects).

To my knowledge, there is no clear statement as to how weak references influence the lifetime of an object in .NET. If they are true weak refs they should not influence it at all, but that would also render them pretty useless for their, I believe, main purpose of caching (am I wrong there?). On the other hand, if they act like soft refs, their name is a little misleading.

Personally, I imagine them to behave like soft references, but that is just an impression and not founded.

Implementation details apply, of course. I'm asking about the mentality associated with .NET's weak references - are they able to expand lifetime, or do they behave like true weak refs?

(Despite a number of related questions I could not find an answer to this specific issue yet.)

Gilford answered 13/10, 2011 at 14:46 Comment(8)
I have never heard that you could take any influence on when exactly an object is reclaimed by the GC, apart from calling GC.Collect(). From that perspective the only thing a Weakreference states is that the object is reclaimable.Loath
@flq: It is possible in, for instance, Java, by selecting either a soft or a weak ref. Soft basically means "I don't mind if this gets claimed but please try to keep it".Gilford
Are you not applying a Java paradigm to C#, in C# and generally a weak reference is just a reference to something that can be collected by the GC at anytime.Heptamerous
@BenRobinson: It should still be possible to differentiate. Unless they explicitly want to stay ambiguous on this matter (which is entirely possible).Gilford
@CodeInChaos: I got this impression from the sources I read on this topic so far, prominently the MSDN. The examples tended to show scenarios in which a soft instead of a weak behavior would be preferable.Gilford
@malfruct should it, why? You can do it in java therefore you should be able to do it in C# does not seem like a particularly valid argument. According to the wikipedia article on weak references soft references are just one of the three types of "non strong" references available in Java. c# does not have these three types and so you are comparing a java feature with something that does not exist in c#. But as code in chaos says, weak references have no impact on the lifetime of the object they are referencing, so they do map to java weak references rather than soft references.Heptamerous
@BenRobinson: Yes, I'm not saying soft refs need to exist in .NET because they exist in Java - I was merely just wondering about the mapping.Gilford
linking to related question #325133Gilford
D
9

I have seen no information that indicates that they would increase the lifetime of the object they point to. And the articles I read about the algorithm the GC uses to determine reachability do not mention them in this way either. So I expect them to have no influence on the lifetime of the object.

Weak
This handle type is used to track an object, but allow it to be collected. When an object is collected, the contents of the GCHandle are zeroed. Weak references are zeroed before the finalizer runs, so even if the finalizer resurrects the object, the Weak reference is still zeroed.

WeakTrackResurrection
This handle type is similar to Weak, but the handle is not zeroed if the object is resurrected during finalization.

http://msdn.microsoft.com/en-us/library/83y4ak54.aspx


There are a few mechanism by which an object that's unreachable can survive a garbage collection.

  • The generation of the object is larger than the generation of the GC that happened. This is particularly interesting for large objects, which are allocated on the large-object-heap and are always considered Gen2 for this purpose.
  • Objects with a finalizer and all objects reachable from them survive the GC.
  • There might be a mechanism where former references from old objects can keep young objects alive, but I'm not sure about that.
Displace answered 13/10, 2011 at 15:3 Comment(2)
Upon further reading, it seems like this is the correct answer. I still could not find a source that explicitly states "does not affect lifetime in any way" though.Gilford
The description of "Weak" vs "WeakTrackResurrection" is vague and not really accurate. A weak handle will be cleared as soon as an object becomes eligible for immediate finalization; a WeakTrackResurrection handle will remain valid until an object ceases to exist or the owner of the handle invalidates it. Unfortunately, when a WeakReference is asked to create a WeakTrackResurrection handle, it's prone to nuke it prematurely unless a strong rooted reference exists to the WeakReference itself.Ouachita
L
14

Are C# weak references in fact soft?

No.

am I wrong there?

You are wrong there. The purpose of weak references is absolutely not caching in the sense that you mean. That is a common misconception.

are they able to expand lifetime, or do they behave like true weak refs?

No, they do not expand lifetime.

Consider the following program (F# code):

do
  let x = System.WeakReference(Array.create 0 0)
  for i=1 to 10000000 do
    ignore(Array.create 0 0)
  if x.IsAlive then "alive" else "dead"
  |> printfn "Weak reference is %s"

This heap allocates an empty array that is immediately eligible for garbage collection. Then we loop 10M times allocating more unreachable arrays. Note that this does not increase memory pressure at all so there is no motivation to collect the array referred to by the weak reference. Yet the program prints "Weak reference is dead" because it was collected nevertheless. This is the behaviour of a weak reference. A soft reference would have been retained until its memory was actually needed.

Here is another test program (F# code):

open System

let isAlive (x: WeakReference) = x.IsAlive

do
  let mutable xs = []
  while true do
    xs <- WeakReference(Array.create 0 0)::List.filter isAlive xs
    printfn "%d" xs.Length

This keeps filtering out dead weak references and prepending a fresh one onto the front of a linked list, printing out the length of the list each time. On my machine, this never exceeds 1,000 surviving weak references. It ramps up and then falls to zero in cycles, presumably because all of the weak references are collected at every gen0 collection. Again, this is the behaviour of a weak reference and not a soft reference.

Note that this behaviour (aggressive collection of weakly referenced objects at gen0 collections) is precisely what makes weak references a bad choice for caches. If you try to use weak references in your cache then you'll find your cache getting flushed a lot for no reason.

Labrecque answered 6/1, 2013 at 20:41 Comment(4)
I'm not sure I can follow. I did not say weak refs should be used for caching, but soft refs should (I think you're saying the same). The MSDN states that "C# weak refs" can be used for caching. So, C# weak refs should be called "soft" if they do, in fact, behave like soft refs.Gilford
I've augmented my answer with two programs that demonstrate the behaviour I was referring to. As you can see, the weak references do not behave like soft references. The example in the MSDN article that you cited is a bad example. You should not use weak references like that. That is not the problem they were designed to solve and they are a poor solution for caching. The main practical applications of weak references are decorating data structures and allowing unreachable subgraphs in a mutable graph to be collected by the GC.Labrecque
"soft refs should". Actually, I wouldn't use soft references for caching either. I'd track memory consumption and clear cache lines more intelligently (e.g. least recently used) rather than let the GC clear them at random in an uncontrolled way. Apparently .NET 4 provides such a cache out-of-the-box but I've never used it.Labrecque
I completely agree with your first comment. The example in the MSDN is misleading/wrong, and the naming of "WeakReference" is correct.Gilford
D
9

I have seen no information that indicates that they would increase the lifetime of the object they point to. And the articles I read about the algorithm the GC uses to determine reachability do not mention them in this way either. So I expect them to have no influence on the lifetime of the object.

Weak
This handle type is used to track an object, but allow it to be collected. When an object is collected, the contents of the GCHandle are zeroed. Weak references are zeroed before the finalizer runs, so even if the finalizer resurrects the object, the Weak reference is still zeroed.

WeakTrackResurrection
This handle type is similar to Weak, but the handle is not zeroed if the object is resurrected during finalization.

http://msdn.microsoft.com/en-us/library/83y4ak54.aspx


There are a few mechanism by which an object that's unreachable can survive a garbage collection.

  • The generation of the object is larger than the generation of the GC that happened. This is particularly interesting for large objects, which are allocated on the large-object-heap and are always considered Gen2 for this purpose.
  • Objects with a finalizer and all objects reachable from them survive the GC.
  • There might be a mechanism where former references from old objects can keep young objects alive, but I'm not sure about that.
Displace answered 13/10, 2011 at 15:3 Comment(2)
Upon further reading, it seems like this is the correct answer. I still could not find a source that explicitly states "does not affect lifetime in any way" though.Gilford
The description of "Weak" vs "WeakTrackResurrection" is vague and not really accurate. A weak handle will be cleared as soon as an object becomes eligible for immediate finalization; a WeakTrackResurrection handle will remain valid until an object ceases to exist or the owner of the handle invalidates it. Unfortunately, when a WeakReference is asked to create a WeakTrackResurrection handle, it's prone to nuke it prematurely unless a strong rooted reference exists to the WeakReference itself.Ouachita
R
-2

Yes
Weak references do not extend the lifespan of an object, thus allowing it to be garbage collected once all strong references have gone out of scope. They can be useful for holding on to large objects that are expensive to initialize but should be avaialble for garabage collection if they are not actively in use.

Rechabite answered 13/10, 2011 at 14:49 Comment(2)
Let me try to be really precise here - do they try to expand the lifetime, or not? Would be great if you could link to a source for further reading.Gilford
o, they simply are ignoerd regarding deciding whether or not to gc an object - they make no decision, thesyj ust do not keep an object alive.Marentic

© 2022 - 2024 — McMap. All rights reserved.