Фрагментация кучи при использовании байтовых массивов - PullRequest
17 голосов
/ 18 апреля 2011

У меня есть приложение на C # 4.0 (один производитель / один потребитель), которое передает огромные объемы данных кусками.Хотя нет нового выделения памяти, через некоторое время у меня кончается память.

Я профилировал память с помощью профилировщика памяти Redgate, и там много свободной памяти.В нем говорится, что свободная память не может быть использована из-за фрагментации.

Я использую блокирующую коллекцию в качестве буфера и байтовые массивы в качестве элементов:

BlockingCollection<byte[]> segments = new BlockingCollection<byte[]>(8);
// producer:
segments.Add(buffer);
// consumer:
byte[] buffer = _segments.Take();

Как можно избежать управляемой фрагментации памяти?

Ответы [ 3 ]

10 голосов
/ 18 апреля 2011

Вы, вероятно, столкнулись с проблемой кучи больших объектов - объекты размером более 85 000 байт помещаются в кучу больших объектов, которая не уплотняется, что может привести к странным ситуациям с нехваткой памяти.Хотя очевидно, что производительность в .NET 4 была улучшена, она далека от идеальной.Решение состоит в том, чтобы в основном использовать свой собственный буферный пул, который содержит несколько статически распределенных фрагментов памяти, и использовать их повторно.
Существует целый ряд вопросов по этому поводу в SO.

Обновление : Microsoft предоставляет менеджер буфера как часть стека WCF.Также есть один на кодпроекте .

4 голосов
/ 18 апреля 2011

Как долго ваш массив байтов []?Они попадают в кучу маленьких или больших объектов?Если вы испытываете фрагментацию памяти, я бы сказал, что они попадают в LOH.

Поэтому вы должны повторно использовать одни и те же байтовые массивы (использовать пул) или использовать меньшие куски.LOH никогда не уплотняется, поэтому он может стать довольно фрагментированным.К сожалению, нет никакого способа обойти это.(Помимо знания этого ограничения и его обхода)

3 голосов
/ 03 июня 2018

GC не сжимает кучу больших объектов для вас, вы все равно можете программно сжимать ее.Следующий фрагмент кода иллюстрирует, как этого можно достичь.

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
...