MTR
MTR

Reputation: 1740

Is this a memory leak, or normal behavior?

While searching for memory leaks, I found a strange thing that I don't know whether it's ok or not.

In order to find memory leaks, I created a little test app with a button new and a button check doing this:

List<WeakReference> WeakReferences = new List<WeakReference>();

private void Button_New(object sender, RoutedEventArgs e)
{
    WeakReferences.Add(new WeakReference(new ObjectUnderTest()));
    // Adding a bunch of other objects to test here
}
private void Button_Check(object sender, RoutedEventArgs e)
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    int AliveCounter = 0;
    foreach (var item in WeakReferences)
    {
        if (item.IsAlive)
        {
            AliveCounter++;
            Debug.WriteLine("Object " + item.Target.GetType().ToString() + " still alive!");
        }
    }
    if (AliveCounter > 0)
    {
        MessageBox.Show(AliveCounter.ToString() + " objects still alive!");
    }
    else
    {
        MessageBox.Show("No objects alive!");
    }
}

Most of my test objects get correctly garbage collected in this scenario, but there are a few objects that are still alive.

After more testing I found that these objects get indeed garbage collected, but only if I switch to another application before clicking the check button.

What do you think, is this normal behavior, or is this a memory leak, that I have to resolve?

Additional Info: At the moment I think this is really a problem, but maybe it will not occure in our production code.

Upvotes: 2

Views: 485

Answers (1)

Adam Ralph
Adam Ralph

Reputation: 29956

When GC.Collect() is called with no GCCollectionMode argument then GCCollectionMode.Default is used which, in most versions of the CLR, is the same as GCCollectionMode.Forced which forces a collection to take place. To ensure that you are forcing a collection, try calling GC.Collect(GCCollectionMode.Forced).

If you still find that objects are being kept alive, this could be due to your thread racing with a concurrent collection (concurrent collection is the default in most environments) or perhaps your ObjectUnderTest type is self-resurrecting or has a complex reference path which is confusing the first pass of the GC (an unlikely scenario but you never know)?

On a general note, the GC will decide when is the best time to collect a given object and this behaviour is non-deterministic (unless you are calling GC.Collect(GCCollectionMode.Forced) or an equivalent). In some edge cases, it is necessary to influence the behavior of the garbage collector but in most cases, it's best to leave GC to do it's thing and not worry about how efficiently it's being done. This is usually efficient enough, and to make it operate more efficiently is likely to be quite difficult and involved.

Upvotes: 5

Related Questions