OutOfMemoryException на конкретной машине при запуске тестов

У нас есть тест тестов NUnit, которые страдают от ошибок OutOfMemoryException на определенной машине.

После расследования кажется, что это не проблема с памятью, а проблема с дескриптором (мы выделяем слишком много объектов Bitmap и не освобождаем их).

Проблема в том, что на одной машине это работает отлично, а на другой - с этой ошибкой.

  1. Сбойная машина — виртуальная машина Hyper-V с Windows7 x64 (6 ГБ оперативной памяти).
  2. Рабочая машина — это физическая машина с Windows XP (2 ГБ оперативной памяти).

Я знаю, что лучшим решением было бы очистить код от любых объектов Bitmap, но мне интересно узнать, почему эти две машины по-разному ведут себя при выполнении одного и того же кода?


person lysergic-acid    schedule 30.09.2013    source источник
comment
Что ж, платформа .NET может быть такой же, но лежащая в ее основе ОС — нет. Ресурсы, такие как растровые изображения, по-прежнему обрабатываются операционной системой. Windows 7 обрабатывает ресурсы иначе, чем Windows XP, поэтому неудивительно, что вы получаете разные результаты в разных версиях Windows.   -  person helb    schedule 30.09.2013
comment
Количество дескрипторов, которые могут просочиться до того, как Windows откажется выдавать, настраивается. Возможно, одна из машин настроена по-другому.   -  person Eric Lippert    schedule 30.09.2013
comment
Спасибо @eric. Вы знаете, откуда это можно контролировать?   -  person lysergic-acid    schedule 30.09.2013
comment
@lysergic-acid: Это сайт вопросов и ответов. Задавайте вопрос как вопрос!   -  person Eric Lippert    schedule 30.09.2013


Ответы (2)


Прочитайте это: http://blogs.technet.com/b/markrussinovich/archive/2010/02/24/3315174.aspx

Вы найдете таблицу различий между различными версиями Windows в отношении кучи GDI. Краткий ответ: XP = ограничение 3 Мб, Win7R2x64 = ограничение 20 Мб. Свободная оперативная память не имеет значения, это жесткие ограничения.

person jlew    schedule 30.09.2013
comment
Это не вяжется с тем, что на XP не вылетает, а на Win7 вылетает :( - person lysergic-acid; 30.09.2013
comment
Мог бы поклясться, что твои условия были обратными тому, что они сейчас - person jlew; 30.09.2013

Это маловероятно, Windows позволит вам слить 10 000 дескрипторов, прежде чем станет раздражаться из-за того, как ведет себя ваша программа, и откажется выделять больше. К тому времени вы израсходовали огромные объемы виртуальной памяти для пиксельных данных в растровых изображениях. Хранится в неуправляемой памяти, сборщик мусора не знает об этом. Пространство виртуальной машины, которое не освобождается, пока вы не вызовете Dispose() или сборщик мусора не позаботится об этом, запустив финализатор.

Сборщик мусора обычно не выполняет свою работу, класс Bitmap — это очень маленький объект, недостаточно большой, чтобы сам по себе запускать сборщик мусора. Вам нужно выделить около 60 000 из них, чтобы вызвать GC. Вы никогда не доберетесь туда, сначала вам не хватит места для виртуальной машины, если только растровые изображения не очень маленькие, а затем обрабатываются. Вызов Dispose() является необязательным, но он перестает быть необязательным для растровых изображений, поскольку финализатор просто не может выполнить работу вовремя.

Объем оперативной памяти не играет никакой роли в этом, программа .NET всегда бомбит ее, не имея возможности найти дыру в адресном пространстве виртуальной машины, достаточно большую, чтобы соответствовать запрошенному размеру. Также проблема с растровыми изображениями, им, как правило, нужны большие дыры. Достаточно загрузить DLL по неудобному базовому адресу, чтобы разрезать большую дыру на две части. В противном случае проблема, которую легко решить, просто установите целевую платформу программы на AnyCPU. Тестовая программа имеет для этого значение конфигурации. Работает на этой машине Win7. Но, конечно, это не веская причина пропускать вызовы Dispose().

person Hans Passant    schedule 30.09.2013