I have a program that does a memory intensive simulation. Below I\'ve written a small console application that replicates the problem I\'m having.
class Prog
This is due to the nature of a concurrentBag (see my earlier question regarding ConcurrentBag ( Possible memoryleak in ConcurrentBag? )).
Basically, a concurrent bag stores items on the local thread. If you dont consume the items, the items will stay on the local thread. Please check the following example:
class TrackedItem
{
public TrackedItem()
{
Console.WriteLine("Constructor!");
}
~TrackedItem()
{
Console.WriteLine("Destructor!");
}
}
static void Main(string[] args)
{
Action allCollect = () =>
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
};
// create a single item and loose it directly thereafter
TrackedItem item = new TrackedItem();
item = null;
allCollect();
// Constructor!, Destructor!
ConcurrentBag bag = new ConcurrentBag();
bag.Add(new TrackedItem());
bag = null;
allCollect();
// Constructor!
// Note that the destructor was not called since there is still a collection on the local thread
Console.ReadLine();
}
The concurrentBag makes use of the ThreadLocal class which makes it convenient to hold 1 instance per thread. The intended way for disposing data in a ThreadLocal is by calling the Dispose method on ThreadLocal (ThreadLocal implements IDisposable). This disposes only the data for the current thread. The concurrentBag doesn't dispose it's ThreadLocals though. Instead it relies on all items being consumed- or a thread hosting the ThreadLocal being disposed. this can be very nasty however when you share threads like within a ThreadPool.