Проходит ли фрагментация памяти на всех кучах в .NET
Что проверяют
Знаете ли вы, что куч в .NET несколько и ведут они себя по-разному. Ответ «да, везде» и ответ «нет, нигде» одинаково плохи: интервьюер хочет услышать, где сборщик мусора уплотняет память, где только освобождает, и что с этим делать на практике.
Как отвечать
Коротко: не на всех и не одинаково.
- куча малых объектов с поколениями 0, 1 и 2: при сборке выжившие объекты копируются и укладываются подряд, дыры схлопываются. Выделение здесь это сдвиг указателя, а не поиск подходящего свободного блока;
- куча больших объектов, куда попадают объекты примерно от 85 килобайт: по умолчанию она не уплотняется, а только подметается, память переиспользуется из списка свободных блоков. Отсюда классическая картина: свободной памяти в процессе много, а запрос на большой массив падает с
OutOfMemoryException; - куча закреплённых объектов: там лежат буферы, закреплённые для работы с неуправляемым кодом, и она не уплотняется по определению.
Дальше про причины и лечение. В куче малых объектов фрагментацию создаёт закрепление: объект под fixed или под GCHandle с типом Pinned сборщик подвинуть не может, вокруг него остаются дыры. Помогают пулы буферов (ArrayPool<byte>) и короткое время закрепления. Для кучи больших объектов есть разовое уплотнение:
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();Это дорогая блокирующая операция, её уместно звать после разовой тяжёлой обработки, а не по таймеру. И скажите, что диагностируется всё счётчиками и дампом, а не на глаз.
Где спотыкаются
Переносят в .NET чужую терминологию и говорят про «молодую» и «старую» кучи. В .NET это поколения внутри одной кучи, а отдельные сущности это куча больших объектов и куча закреплённых, и вопрос именно про них.
Второе: утверждают, что фрагментация сильнее всего в нулевом поколении. Ровно наоборот, оно уплотняется на каждой сборке, а копится проблема там, где уплотнения нет.
Третье: назначают лекарством регулярный GC.Collect(). Принудительная сборка сама по себе не уплотняет кучу больших объектов и при этом продвигает выжившие объекты в старшие поколения, то есть делает хуже.