C # ConcurrentBag memory consumption during iteration

This is easier if I start by posting the code:

static void Main(string[] args)
{
    List<double> testLst = new List<double>();
    for (int i = 0; i < 20000000; i++) { testLst.Add(i); }

I filled out a list with 20,000,000 items. In the task manager, I see that this process uses ~ 300 MB. If I iterate over the list using the foreach loop:

    foreach (var a in testLst.Take(10)) 
    {
        Console.WriteLine(a);
    }
}

Memory usage does not increase (I set a breakpoint on Console.WriteLine and, as I said, I measure it using the task manager). Now, if I replaced List with ConcurrentBag:

static void Main(string[] args)
{
    ConcurrentBag<double> testCB = new ConcurrentBag<double>();
    for (int i = 0; i < 20000000; i++) { testCB.Add(i); }

    foreach (var a in testCB.Take(10)) 
    {
        Console.WriteLine(a);
    }
}
Memory usage

is 450 ~ 500 MB before the foreach loop. The question arises: why, if a transition up to ~ 900 MB is used inside the foreach-loop?

I expect ConcurrentBag to consume more memory compared to the list, but I don't understand why so much memory is used for iteration.

( ConcurrentBag , , , )

+4
1

ConcurrentBag.GetEnumerator docs ( ):

. , GetEnumerator. .

source, , :

public IEnumerator<T> GetEnumerator()
{
    // Short path if the bag is empty
    if (m_headList == null)
        return new List<T>().GetEnumerator(); // empty list

    bool lockTaken = false;
    try
    {
        FreezeBag(ref lockTaken);
        return ToList().GetEnumerator();
    }
    finally
    {
        UnfreezeBag(lockTaken);
    }
}

, ToList() List<T> ( , -).

As a side note, that line is return new List<T>().GetEnumerator();not very ... that could write return Enumerable.Empty<T>().GetEnumerator();.

+9
source

All Articles