Почему GC не собирает неиспользуемые объекты?

Я реализовал шаблон Producer/Consumer с BlockingCollection для своего эксперимента.

PerformanceCounter c = null;
void Main()
{
    var p  =System.Diagnostics.Process.GetCurrentProcess();
    c = new PerformanceCounter("Process", "Working Set - Private", p.ProcessName);

    (c.RawValue/1024).Dump("start");
    var blocking = new BlockingCollection<Hede>();
    var t = Task.Factory.StartNew(()=>{
        for (int i = 0; i < 10000; i++)
        {
            blocking.Add(new Hede{
            Field = string.Join("",Enumerable.Range(0,100).Select (e => Path.GetRandomFileName()))
            });
        }
        blocking.CompleteAdding();
    });

    var t2 = Task.Factory.StartNew(()=>{
        int x=0;
        foreach (var element in blocking.GetConsumingEnumerable())
        {
            if(x % 1000==0)
            {
                (c.RawValue/1024).Dump("now");
            }
            x+=1;   
        }
    });
    t.Wait();
    t2.Wait();
    (c.RawValue/1024).Dump("end");
}

Мой дамп памяти после запуска:

start
211908
now
211972
now
212208
now
212280
now
212596
now
212736
now
212712
now
212856
now
212840
now
212976
now
213036
end
213172

Моя память составляет 211908 КБ до потребления, но она увеличивается один за другим при производстве из другого потока.

Сборщик мусора не собирал созданные объекты из памяти. Почему у меня увеличивается память, хотя реализован шаблон производитель/потребитель?


person oguzh4n    schedule 02.01.2012    source источник
comment
Я не вижу никаких вызовов Dispose или Using. Я вижу, вы добавляете элементы в коллекцию и никогда не удаляете их. Я не совсем понимаю, в чем проблема или чего вы пытаетесь достичь.   -  person Origin    schedule 02.01.2012
comment
Я не очень понимаю, чего вы ожидаете?   -  person Tudor    schedule 02.01.2012
comment
Происхождение: это шаблон производителя/потребителя, мне не нужно удалять элемент из списка. GetConsumingEnumerable() удаляет элемент для меня   -  person oguzh4n    schedule 02.01.2012
comment
Ваши результаты не указывают на утечку или что-то в этом роде. Многие элементы потребляют память, и ваша разница крошечная. Запустите его на 2 дня, и он, вероятно, стабилизируется.   -  person Henk Holterman    schedule 02.01.2012
comment
Ваш заголовок не соответствует вашему вопросу! GC собирает неиспользуемые объекты, когда так решает. Поскольку вызовов GC.Collect нет, вы измеряете просто, если ваша программа создает объекты.   -  person Alexei Levenkov    schedule 02.01.2012
comment
Возможно, вам стоит попробовать метод GetTotalMemmory (msdn.microsoft.com/en -us/library/system.gc.gettotalmemory.aspx) вместо этого счетчика, поскольку кажется, что это не такая уж и точная единица измерения, как описано здесь: stackoverflow.com/questions/2611141/   -  person Ernesto    schedule 03.01.2012


Ответы (2)


ConcurrentQueue<T>, который по умолчанию используется BlockingCollection<T> , содержит утечку памяти в .Net 4.0. Я не уверен, что это проблема, которую вы наблюдаете, но это может быть.

Это должно быть исправлено в грядущей версии .Net 4.5.

person svick    schedule 02.01.2012
comment
Хотя это верно в отношении ConcurrentQueue, «утечка» никогда не будет больше, чем неиспользуемая часть очереди. Обычно вы бы использовали верхнюю границу, например new BlockingCollection<Hede>(100), и тогда вы могли бы запускать это вечно. - person Henk Holterman; 02.01.2012
comment
@Henk, да, но с кодом в вопросе очередь не имеет границ, и вполне возможно, что сначала она будет заполнена полностью, и только потом предметы будут израсходованы. Если это так, то все предметы будут течь. - person svick; 02.01.2012

Сборщик мусора не всегда автоматически освобождает память. Вы можете форсировать сборку мусора, вызвав GC.Collect(); после удаления неиспользуемых объектов.

person Dennis Traub    schedule 02.01.2012
comment
я пробовал GC.Collect();GC.WaitForPendingFinalizers();GC.Collect(); после t2.Wait(); строки, не имеет значения - person oguzh4n; 02.01.2012