Оптимизация памяти с помощью ArrayPool в C#
В C# пул массивов представлен классом ArrayPool<T>. Это потокобезопасный класс, предоставляющий структурированный механизм для эффективного управления и повторного использования массивов типа T.
var arrPool = ArrayPool<int>.Shared;Здесь мы создаём пул целочисленных массивов, который используется во всём приложении. Он имеет максимальную длину массива по умолчанию, равную 2^20 (1024*1024 = 1.048.576) байт.
Также можно использовать метод расширения Create():
var arrPool = ArrayPool<int>.Create(100, 10);Здесь первый аргумент метода Create() устанавливает максимальную длину массива в ArrayPool. Второй аргумент определяет количество массивов в сегменте. Пул группирует массивы одинаковой длины в эти сегменты, чтобы мы могли быстрее получить к ним доступ. Однако ограничивать пулы массивов этими параметрами нужно с осторожностью. Если мы превысим лимиты, произойдёт выделение памяти для нового массива.
Использование:
var pool = ArrayPool<int>.Shared;Сначала мы инициализируем пул, затем используем метод Rent() для получения массива длиной size из пула.
var size = 10;
var arr = pool.Rent(size);
for (var i = 0; i < size; i++)
arr[i] = i * 2;
Console.WriteLine("Элементы:");
for (var i = 0; i < size; i++)
Console.Write(arr[i] + " ");
pool.Return(arr);
// ВыводВ конце мы должны использовать метод Return(), чтобы отправить массив обратно в пул. Таким образом, он снова доступен для следующего использования.
Элементы:
0 2 4 6 8 10 12 14 16 18
Здесь следует отметить, что фактический размер массива, который мы получаем из ArrayPool, как минимум равен размеру, который мы запрашиваем. Т.е. полученный массив может иметь большую длину. ArrayPool состоит из массивов с размерами, равными степени 2, начиная с длины 16. Таким образом, когда мы запрашиваем массив определённого размера, мы получаем ближайший доступный массив как минимум этого размера. В примере выше размер массива будет 16, а не 10.
Использование ArrayPool не только значительно быстрее, но и эффективно использует память. ArrayPool не выделяет память (кроме изначальной инициализации). Поэтому при интенсивном переиспользовании массивов разница между pool.Rent() и new становится огромной.
Итого
ArrayPool — отличный выбор, когда нужно оптимизировать память и уменьшить её фрагментацию, особенно в сценариях, где производительность критична. Он позволяет повторно использовать существующие блоки памяти посредством переиспользования массива. Однако придётся явно возвращать взятые массивы в пул с помощью метода Return(). Кроме того, арендованный массив может иметь размер, превышающий тот, который нам действительно нужен, что потребует специальных манипуляций для соответствия нашему конкретному сценарию использования. В приложениях, где производительность критична, и где часто используются и инициализируются массивы, предпочтительным вариантом является ArrayPool, тогда как для более простых случаев использования с менее частым созданием массивов предпочтительнее будет new.
Источник: https://code-maze.com/csharp-arraypool-memory-optimization/