OutOfMemoryException - PullRequest
       13

OutOfMemoryException

2 голосов
/ 07 апреля 2010

У меня есть приложение, которое довольно жадно до памяти. Он содержит большой объем данных в некоторых больших массивах.

Недавно я заметил случайное исключение OutOfMemoryException. Эти OutOfMemoryExceptions возникают задолго до того, как мое приложение (ASP.Net) израсходовало 800 МБ, доступных для него. Я проследил проблему до области кода, где размер массива изменен. Массив содержит структуру размером 74 байта. (Я знаю, что вы не должны создавать структуры, размер которых превышает 16 байт), но это приложение является портом из приложения Vb6). Я попытался изменить структуру на класс, и это, похоже, решило проблему на данный момент.

Я думаю, что причина, по которой переход на класс решает проблему, связана с тем фактом, что при использовании структуры и изменении размера массива необходимо зарезервировать сегмент памяти, достаточно большой для хранения нового массива ( например (currentArraySize + увеличенияBySize) * 74) не может быть найден. Это приводит к исключению OutOfMemoryException.

Это не относится к классу, поскольку каждому элементу массива требуется только 8 байтов для хранения указателя на новый объект.

Правильно ли мое мышление здесь?

Ответы [ 4 ]

3 голосов
/ 07 апреля 2010

Ваши предположения относительно того, как хранятся массивы, верны. Переход от структуры к классу добавит немного накладных расходов для каждого экземпляра, и вы потеряете преимущества локальности, так как все данные должны собираться через ссылку, но, как вы заметили, это может решить вашу проблему с памятью на данный момент.

2 голосов
/ 07 апреля 2010

Проблема, с которой вы столкнулись, может быть вызвана фрагментацией кучи больших объектов, а не нормальным состоянием нехватки памяти, когда вся память действительно израсходована.

См. http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

Решение может быть таким же простым, как увеличение массива большими фиксированными приращениями, а не меньшими случайными приращениями, чтобы по мере освобождения массивов блоки памяти LOH можно было повторно использовать для нового большого массива.

Это также может объяснить проблему struct-> class, поскольку структура, вероятно, хранится в самом массиве, в то время как класс будет маленьким объектом в куче маленьких объектов.

2 голосов
/ 07 апреля 2010

Когда вы изменяете размер массива, он создает новый для хранения новых данных, затем копирует данные, и у вас будет две копии одинаковых данных в памяти одновременно. Как вы и ожидали.

При использовании структур массив будет занимать struct size * number of elements. При использовании класса он будет содержать только указатель.

Тот же сценарий также подходит для List, размер которого со временем увеличивается, поэтому разумно инициализировать его ожидаемым количеством элементов, чтобы избежать изменения размера и копирования.

В 32-битных системах вы получите около 800 МБ, как вам известно. Одно из решений, которое вы можете попробовать, - это сохранить свои структуры на диске и читать их при необходимости. Поскольку они имеют фиксированный размер, вы можете легко перейти в правильную позицию в файле.

У меня есть проект на Codeplex для обработки больших объемов данных. Он имеет тип массива с возможностью автоматического роста, который может помочь вашему сценарию, если у вас возникнут проблемы с сохранением всего этого в памяти.

0 голосов
/ 02 января 2015

.NET Framework 4.5.1 имеет возможность явно сжимать кучу больших объектов (LOH) во время сборки мусора.

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();

См. Дополнительную информацию в: GCSettings.LargeObjectHeapCompactionMode

И вопрос по этому поводу: Сжатие кучи больших объектов, когда это хорошо?

...