Для чего нужно разделение между Large Object Heap и Small Object Heap в .NET?

«Для чего нужно разделение между Large Object Heap и Small Object Heap в .NET?» — вопрос из категории Управление памятью, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Разделение на Large Object Heap (LOH) и Small Object Heap (SOH) в .NET оптимизирует управление памятью и производительность сборки мусора (GC). Объекты размером ≥85 КБ размещаются в LOH, меньшие — в SOH.

Основные причины разделения:

  1. Минимизация фрагментации: Перемещение (компактирование) крупных объектов при сборке мусора — дорогая операция, которая может привести к сильной фрагментации кучи. LOH по умолчанию не компактируется (хотя в .NET 4.5.1+ появилась возможность принудительной компактировки через GCSettings.LargeObjectHeapCompactionMode).
  2. Оптимизация производительности: Выделение памяти для больших объектов в LOH происходит иначе — без частых операций копирования между поколениями (Gen0, Gen1), что снижает накладные расходы GC.

Пример на C#:

// Попадает в SOH (размер < 85 КБ)
byte[] smallArray = new byte[10_000];

// Попадает в LOH (размер ≥ 85 КБ)
byte[] largeArray = new byte[100_000];

Важные особенности LOH:

  • Очистка LOH происходит только во время сборки мусора поколения 2 (Full GC).
  • Частое создание и освобождение крупных объектов может привести к фрагментации LOH и, как следствие, к исключению OutOfMemoryException, даже если общий объем свободной памяти достаточен.