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

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

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

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

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

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

3 ответа

Решение

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

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

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

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

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

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
Другие вопросы по тегам