OutOfMemoryException выбрасывается, пока память еще доступна - PullRequest
7 голосов
/ 26 мая 2009

Мне нужно создать большой список строк и сохранить его в памяти, однако при его создании генерируется исключение OutOfMemoryException. Согласно Resource Monitor у меня все еще есть 1 ГБ памяти. Я нашел эту статью базы знаний , посвященную этой проблеме, но похоже, что она должна была быть исправлена ​​в framework 1.1 SP1 (я использую 3.5 sp1).

Кто-нибудь может пролить свет на то, что происходит за кулисами? Ограничивает ли .net Framework, сколько памяти может быть использовано одним процессом (в 32-битной системе)? Если так, я могу понять, почему, но что не имеет смысла, так это то, что приложение использует только 1,6 ГБ, а системе еще остается ~ 1 ГБ.

Редактировать - Для тех, кто спросил здесь, есть более подробная информация:

У меня есть список (да, я мог бы использовать что-то еще, но сейчас я просто создаю прототипы), я генерирую случайную строку, выполняя Guid.NewGuid (). ToString (), и добавляю ее в список , Я пытаюсь сгенерировать список с таким количеством элементов, сколько я могу в него вписать, и протестировать различные методы поиска конкретного. Мое первое предположение состояло в том, что происходит некоторая фрагментация, но я отбросил все, кроме приведенного ниже кода, и это все еще происходит. Я не думаю, что этот маленький фрагмент может привести к фрагментации, но я, вероятно, ошибаюсь.

        List<string> blah = new List<string>();

        for (int i = 0; i < 50000000; i++)
        {
            blah.Add(Guid.NewGuid().ToString());
        }

Ответы [ 5 ]

9 голосов
/ 26 мая 2009

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

Это также приведет к OutOfMemoryException.

Насколько велик список, другими словами, сколько у вас строк, точно или примерно, когда вы получаете исключение?

А как вы заполняете список? Знаете ли вы заранее, сколько предметов вы собираетесь добавить? И если да, укажите ли вы емкость при создании списка?

Если вы не знаете, возможно ли это выяснить, чтобы вы могли указать эту емкость?

9 голосов
/ 26 мая 2009

Win32 имеет ограничение 2 ГБ на процесс для памяти. Ну, на самом деле 4 ГБ, но 2 ГБ зарезервированы для режима ядра, если только у вас не установлена ​​опция запуска ОС / 3 ГБ .

2 голосов
/ 27 мая 2009

Конструктор по умолчанию List начинается с пустого массива в качестве внутреннего хранилища. Вызов Add (T item) проверяет необходимость изменения размера массива и удваивает свойство Capacity (через метод EnsureCapacity). Когда свойство Capacity установлено, оно ...

  1. Создает новый массив с новым размером (удваивает оригинал!)
  2. Копирует элементы из старого в новый.
  3. Изменяет внутреннюю ссылку на новую.

Итак, если предположить, что Capacity n означает, что во время изменения размера у вас будет общее использование памяти 3n.

Сколько элементов содержится в вашем Списке, когда он выходит из строя? Попробуйте использовать конструктор, который принимает емкость, если вы знаете, сколько элементов будет добавлено. Это позволяет избежать любых изменений размера, которые могут потребоваться (и может вызвать прямое исключение OutOfMemoryException, если вам требуются огромные блоки памяти).

1 голос
/ 28 марта 2013

Забудьте о фрагментации, LargeAddressAware или gcAllowVeryLargeObjects ... Моя проблема с этой конкретной ситуацией была решена снятием флажка «Предпочитать 32-битный» на странице свойств моего проекта консоли в разделе «Сборка». Это было установлено по умолчанию ... почему?

0 голосов
/ 26 мая 2009

Я действительно не знаю специфики этой ошибки, но я сталкивался с этим или с чем-то очень похожим много лет назад. По сути, мы обнаружили, что существует жесткое ограничение на количество дескрипторов GDI, с которыми связано ваше приложение. Что-то вроде 9,999. При достижении этого предела приложение будет аварийно завершать работу с исключением из-за недостатка памяти независимо от того, сколько памяти было свободно.

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

См. Эти ссылки для получения дополнительной информации

http://www.simple -talk.com / DotNet / .net-каркасные /-опасности-оф-большого объекта кучи / http://msdn.microsoft.com/en-us/magazine/cc534993.aspx http://blogs.msdn.com/maoni/archive/2006/04/18/large-object-heap.aspx http://social.msdn.microsoft.com/Forums/en-US/clr/thread/08e6bd5f-613e-41ae-9ab1-b05c7ff2710f

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...