3

Possible Duplicate:
Possible memoryleak in ConcurrentBag?

I have epic memory leak in my app. All data, that i add in local concurrentBag collection in one of methods, was never collected.

This simple code demonstrate, how I use it:

void Main()
{
    var l = new List<int>(){1,2,3,4};
    Func(l);
    l.Clear();
    l=null;
}

void Func(List<int> list)
{
    var bag = new ConcurrentBag<int>();
    Parallel.ForEach(list, k=> bag.Add(++k));

    list.Clear();

    foreach(int i in bag) //I know, I doing it wrong.
    {
        list.Add(i);
    }
}

What I expect: bag will be created and dispose at method "Func".

What I see: bag is never dispose, hold all threads that created in Parallel.ForEach, hold all data, that I add in it. =(

Okay, I can use "TryTake" to remove item from bag, when I add it in list. But empty bag is still hold in memory.

Now I resolve problem by using List instead of ConcurrentBag. But I can't sleep well since I seen this in my memory proflier. Sorry for my eng =)

UPDATE

I change my method "Func":

void Func(List<int> list)
{
    var bag = new ConcurrentBag<int>();
    Parallel.ForEach(list, k=> bag.Add(++k));

    list.Clear();

    int i;
    while(bag.TryTake(out i))
    {
        list.Add(i);
    }

    bag = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

Then I create project in VS, compile and run my program. This instance graph was been created by ".Net Memory Profiler 4.0" from memory snapshot, that I collect in 10 minutes after program have done all work:

http://xmages.net/storage/10/1/0/f/d/upload/4c67f305.jpg (sorry, just can't post images)

Community
  • 1
  • 1
svs-t
  • 33
  • 1
  • 4
  • 1
    Is there any indication that the memory is *never* garbage collected? Just because it's present for a while doesn't mean it's a permanent leak. Maybe `ConcurrentBag` uses finalizers (quite possibly in internal types) which mean it takes longer to collect the associated memory? – Jon Skeet Feb 13 '12 at 07:14
  • post updated with adding memory profiler report – svs-t Feb 13 '12 at 08:19
  • Why is "Gc.Collect" and "Gc.WaitForPendingFinalisers" required to prevent this memory leak? – rollsch Apr 09 '18 at 23:35

1 Answers1

9

This is because a concurrent bag adds items to the local storage of a thread. The reference from the local storage of a thread to the bag is a strong reference so as long as there is still 1 item in the bag, it ensures that at least 1 thread references the Bag and it wont be collected. Consume all items from the bag or use a different container.

Please see: Possible memoryleak in ConcurrentBag?

Community
  • 1
  • 1
Polity
  • 14,734
  • 2
  • 40
  • 40
  • 1
    post updated. Now all items removed. Why objects "ThreadLocalList" are already alive? – svs-t Feb 13 '12 at 08:20
  • I have read this but not found answer on my question). I know about several storages in ConcurrentBag. I don't understand, why they are newer collecting by GC, although all items and references are removed. – svs-t Feb 13 '12 at 08:52
  • 1
    I've been checking and i quess http://stackoverflow.com/questions/6944938/does-net-threadpool-thread-get-reset-when-it-goes-back-to-the-pool can give us the answer – Polity Feb 13 '12 at 09:13
  • Thank you for useful information! – svs-t Feb 13 '12 at 10:11