Skip to content

ConditionalWeakTable causes a memory leak if one of their values references the table #12255

@kpreisser

Description

@kpreisser

Hi,

I found an odd behavior of System.Runtime.CompilerServices.ConditionalWeakTable<TKey, TValue> in both .NET Core and .NET Framework which looks like a bug to me: If you create multiple instances of the ConditionalWeakTable and store a key-value pairs in them, where the key stays alive and the value contains a reference to the ConditionalWeakTable, the values are not garbage-collected after they (and the ConditionalWeakTables) are no longer referenced.

For example, create a .NET Core Console application with the following code:

using System;
using System.Runtime.CompilerServices;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            object key = new object();
            while (true) {
                var table = new ConditionalWeakTable<object, Tuple<object, byte[]>>();
                table.Add(key, new Tuple<object, byte[]>(table, new byte[1000000]));

                GC.Collect();
            }
        }
    }
}

Expected behavior: The memory consumption of the program should stay in the same area, because when a new ConditionalWeakTable instance is created, there are no more references to the previous ConditionalWeakTable and its Tuple value, so they should be able to be reclaimed by the Garbage Collector.

Actual behavior: The memory consumption rises rapidly (4 GB after some seconds) until an OutOfMemoryException is thrown, as the byte arrays are not reclaimed by the garbage collector.

However, if you remove the reference to the table by replacing table.Add(...) with table.Add(key, new Tuple<object, byte[]>(null, new byte[1000000])), the problem disappears.

If the algorithm cannot be implemented such that it can detect that there are no more references to the table and its values, I think the ConditionalWeakTable should implement a Dispose() method that allows to clear all key-value-pairs.

The behavior is the same for .NET Core (.NETCoreAPP 1.1) and .NET Framework 4.6.2.

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions