Garbage Collection should have removed object but WeakReference.IsAlive still returning true

后端 未结 5 957
时光说笑
时光说笑 2020-12-06 05:50

I have a test that I expected to pass but the behavior of the Garbage Collector is not as I presumed:

[Test]
public void WeakReferenceTest2()
{
    var obj =         


        
5条回答
  •  甜味超标
    2020-12-06 06:22

    There are a few potential issues I can see:

    • I am unaware of anything in the C# specification which requires that the lifetimes of local variables be limited. In a non-debug build, I think the compiler would be free to omit the last assignment to obj (setting it to null) since no code path would cause the value of obj will never be used after it, but I would expect that in a non-debug build the metadata would indicate that the variable is never used after the creation of the weak reference. In a debug build, the variable should exist throughout the function scope, but the obj = null; statement should actually clear it. Nonetheless, I'm not certain that the C# spec promises that the compiler won't omit the last statement and yet still keep the variable around.

    • If you are using a concurrent garbage collector, it would may be that GC.Collect() triggers the immediate start of a collection, but that the collection wouldn't actually be completed before GC.Collect() returns. In this scenario, it may not be necessary to wait for all finalizers to run, and thus GC.WaitForPendingFinalizers() may be overkill, but it would probably solve the problem.

    • When using the standard garbage collector, I would not expect the existence of a weak reference to an object to prolong the existence of the object in the way that a finalizer would, but when using a concurrent garbage collector, it's possible that abandoned objects to which a weak reference exists get moved to a queue of objects with weak references that need to be cleaned up, and that the processing of such cleanup happens on a separate thread that runs concurrently with everything else. In such case, a call to GC.WaitForPendingFinalizers() would be necessary to achieve the desired behavior.

    Note that one should generally not expect that weak references will be invalidated with any particular degree of timeliness, nor should one expect that fetching Target after IsAlive reports true will yield a non-null reference. One should use IsAlive only in cases where one wouldn't care about the target if it's still alive, but would be interested in knowing that the reference has died. For example, if one has a collection of WeakReference objects, one may wish to periodically iterate through the list and remove WeakReference objects whose target has died. One should be prepared for the possibility that WeakReferences might remain in the collection longer than would be ideally necessary; the only consequence if they do so should be a slight waste of memory and CPU time.

提交回复
热议问题