Фрагментация кучи .NET Core при использовании ArrayPool - «свободное» пространство, занимающее много памяти - PullRequest
0 голосов
/ 24 октября 2019

У меня есть серверное приложение .NET Core 2.0 с пользовательским классом коллекции, похожим на OrderedDictionary, который хранит массив T [] внутри. Многие из них были выделены для каждого запроса к приложению, поэтому они занимали много оперативной памяти и иногда вызывали огромные сборки мусора 2-го поколения, которые замораживали все приложение на 10-30 секунд. Многие из этих массивов были достаточно большими, чтобы попасть в кучу больших объектов.

В попытке исправить это, я попытался использовать ArrayPool для повторного использования массивов. Это значительно уменьшило частоту и продолжительность зависаний ГХ, но заставило приложение использовать гораздо больше ОЗУ. Сумма, сообщаемая GC.GetTotalMemory(), аналогична при использовании ArrayPool, но значение Private Bytes (в Windows) или RSS + Swap (в Linux) выше на 50-60%. Используя SOS !dumpheap -stat, я вижу, что есть много «свободных» фрагментов, поэтому это выглядит как фрагментация кучи .NET.

Если я принудительно сжимаю GC с

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect(2, GCCollectionMode.Default, true, true);

PrivateЗначение Bytes / RSS + Swap версии ArrayPool снижается примерно до 120% от версии, отличной от ArrayPool, но со временем, когда приложение обрабатывает больше запросов, оно снова достигает 150%.

Почему этопроисходит и как я могу предотвратить эту потерю оперативной памяти?

...