Ответ
Исключение OutOfMemoryException возникает, когда среде выполнения CLR не удается выделить новую память в управляемой куче. Вот типичные сценарии, которые могут к этому привести:
1. Непрерывное выделение больших массивов или объектов
Самый прямой способ — быстрое и неограниченное создание объектов, с которым сборщик мусора (GC) не успевает справиться.
// Пример 1: Создание больших массивов
List<byte[]> memoryHog = new List<byte[]>();
try
{
while (true)
{
// Выделяем блок по 100 МБ
memoryHog.Add(new byte[100 * 1024 * 1024]);
}
}
catch (OutOfMemoryException ex)
{
Console.WriteLine($"Out of Memory: {ex.Message}");
}
2. Утечки памяти через долгоживущие ссылки
Объекты, на которые сохраняются ссылки, никогда не собираются GC. Частая причина — статические коллекции.
public static class MemoryLeak
{
// Статическая коллекция живет всё время работы домена приложения
private static List<byte[]> _globalCache = new List<byte[]>();
public static void CauseLeak()
{
// Каждый добавленный массив никогда не будет удален
for (int i = 0; i < 10000; i++)
{
_globalCache.Add(new byte[10 * 1024 * 1024]); // 10 МБ
}
}
}
3. Фрагментация Large Object Heap (LOH)
Объекты размером >= 85 000 байт размещаются в LOH. LOH не компактифицируется по умолчанию (до .NET 4.5.1), что может привести к фрагментации и невозможности найти непрерывный блок памяти для нового большого объекта, даже если свободной памяти в сумме много.
// Чередование больших и маленьких объектов может фрагментировать LOH
var largeObjects = new List<byte[]>();
for (int i = 0; i < 1000; i++)
{
// Создаем большой объект
largeObjects.Add(new byte[85000]);
// Создаем много маленьких объектов, которые умирают и оставляют "дыры"
var temp = new byte[100];
}
// В какой-то момент выделение нового большого массива может не удасться
byte[] failedAllocation = new byte[85000]; // Возможен OutOfMemoryException
4. Ограничения процесса и среды
- 32-битные приложения: Имеют ограничение адресного пространства в ~2 ГБ (или ~3-4 ГБ с флагом
LARGEADDRESSAWARE). - 64-битные приложения: Теоретически ограничены объемом физической памяти и файла подкачки, но на практике могут столкнуться с ограничениями среды выполнения или фрагментацией.
Важное отличие: OutOfMemoryException относится к куче (heap). StackOverflowException — это отдельное исключение, связанное с переполнением стека вызовов (stack), обычно из-за бесконечной или слишком глубокой рекурсии.