На днях, при отладке профайлера, на приложении выделяющим и инициализирующим массив в 2Gb (максимальный размер объекта в CLR), во время очередного GC, был замечен странный кратковременный всплеск потребления памяти - выделялось дополнительно еще 2Gb (итого пиково было 4Gb). После расследования выяснилось, что на время вызова ICorProfilerCallback::ObjectReferences() CLR выделяет массив для передачи в профайлер всех исходящих рефернсов соответствующего объекта. Если референсы занимают эти самые 2Gb, то будут выделен массив в 2Gb. Проблема возникает только тогда, когда ICorProfilerCallback::ObjectReferences() возвращает всегда S_OK и производится полный обход графа для профайлера.
Собственно приложение (число 9 в коде подобрано для CLR 4.0 x64):
using System;
namespace AllocationTest
{
internal class Program
{
private static void Main()
{
var tmp = new object[0x80000000U / (uint) IntPtr.Size - 9];
for (int n = 0; n < tmp.Length; ++n)
tmp[n] = tmp;
Console.Write("Press any key...");
Console.ReadKey();
Console.WriteLine();
GC.KeepAlive(tmp);
}
}
}
P.S. Если убрать в примере запонение массива, то эффект наблюдается не будет.
P.P.S.CLR v4.5 x64 может выделять массивы больше чем 2Gb! Смотри
gcAllowVeryLargeObjects.