Почему нехватка памяти зависит от промежуточных вызовов GC.GetTotalMemory? - PullRequest
2 голосов
/ 17 августа 2010

Программе с большим объемом памяти, которую я написал, не хватило памяти: возникло исключение OutOfMemory. Во время попыток уменьшить использование памяти я начал вызывать GC.GetTotalMemory (true) (чтобы записать общее использование памяти в файл отладки), что вызывает сборку мусора.

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

Может кто-нибудь объяснить, почему исключение нехватки памяти выдается только тогда, когда нет вызовов GC.collect?

Обновление:

Я использую VS 2010, но я нацеливаю приложение на фреймворк 3.5. Я считаю, что дефрагментация действительно вызывает мои проблемы.

Я провел несколько тестов: когда генерируется исключение, вызов GC.gettotalmemory говорит мне, что я использую ~ 800 * 10 ^ 6 байт. Тем не менее, диспетчер задач говорит мне, что приложение использует 1700 МБ. Довольно большое расхождение. Сейчас я планирую выделить память только один раз и никогда не освобождать большие массивы, а использовать их повторно. К счастью, моя программа позволяет мне выполнять это без особых хлопот.

Ответы [ 6 ]

4 голосов
/ 18 августа 2010

Я решил проблему, применив более умное управление памятью.В частности, с помощью CustomList в соответствии с предложениями на http://www.simple -talk.com / dotnet / .net-framework / куча-опасности-большого-объекта-объекта /

2 голосов
/ 17 августа 2010

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

1 голос
/ 17 августа 2010

Я вполне уверен, что нехватка памяти не вызывает сборку мусора. Возможно, это звучит невероятно не интуитивно, но я думаю, что это было сделано по уважительной причине. Это не дает программе войти в смертельную спираль, где она постоянно пытается найти больше места и надежно поместить все объекты в поколение №2. Из которого очень трудно восстановить.

Аргумент true , передаваемый GetTotalMemory (), вызывает полную сборку мусора. Я предполагаю, что это происходит, чтобы освободить достаточно места в куче больших объектов, чтобы удовлетворить выделение памяти. Это, конечно, будет работать только один раз. Если ваша программа просто продолжает работать, сжимая память за 1,5 гигабайта или около того, чтобы она уже использовалась, то OOM снова не за горами. На этот раз без какого-либо способа восстановить. Выживание OOM требует радикальных мер.

Вам понадобится хороший профилировщик памяти, чтобы узнать, что на самом деле происходит . Неуправляемый C ++ в вашем проекте всегда является источником утечек памяти. Неуправляемый вид, всегда трудный для устранения проблем.

0 голосов
/ 17 августа 2010

Я просматривал сайт Microsoft Connect и вижу сообщения об ошибках, в которых люди заявляют, что вы тоже.Утверждение состоит в том, что происходит OutOfMemoryException, который может быть решен путем периодического вызова GC.Collect.Я видел один отчет , в котором ведущий инженер из команды сборщика мусора ответил и сказал, что в .NET 4.0 исправлена ​​ошибка, которая должна была решить проблему фрагментации с кучей больших объектов.Вот почему я спросил, какую версию вы используете.

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

Мой совет:

  • убедитесь, что у вас установлены последние исправления и пакет обновления
  • рефакторинг кода, чтобы он не занимал слишком много памяти
  • повторное использование объектов LOH в максимально возможной степени вместо создания новых
  • продолжайте использовать GC.Collect в стратегических точках, если необходимо в качестве обходного пути
0 голосов
/ 17 августа 2010

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

Если вы выполняете большие неуправляемые выделения, вы можете использовать GC.AddMemoryPressure , чтобы сообщить об этом GC, чтобы он мог принять это во внимание при принятии решения о запуске коллекции или нет.

0 голосов
/ 17 августа 2010

GC.Collect - это просто «предложение» освободить неиспользуемую память - оно не гарантирует ее освобождение.

[Править] Похоже, что когда-то верно, когда я изучал JVM много лет назадможет быть не так в .NET больше.В библиотеке MSDN говорится, что GC.Collect «Принудительно производит немедленную сборку мусора для всех поколений».Хорошие вещи (для меня, во всяком случае) об этом здесь .

...