2009-09-21 8 views
5

Наше приложение не работает на одном компьютере конкретного пользователя с ERROR_NOT_ENOUGH_MEMORY («Недостаточно памяти для обработки этой команды»).Устранение неисправностей ERROR_NOT_ENOUGH_MEMORY

Ошибка, по-видимому, возникает где-то глубоко в рамках среды Delphi VCL, которую мы используем, поэтому я не уверен, какая функция Windows API несет ответственность.

Является ли память проблемой? Вызов GlobalMemoryStatus дает следующую информацию:

  • dwTotalPhys - 1063150000 (~ 1 Гб)
  • dwAvailPhys - 26735000 (~ 27 MB)
  • dwAvailPage - 1489000000 (~ 1,4 Гб)

Мне кажется странным, что Windows позволила бы доступной физической памяти стать настолько низкой, когда в файле подкачки будет доступно столько места, но я недостаточно знаю об управлении виртуальной памятью Windows, чтобы узнать, нормально это или нет. , Это?

Если нет памяти, то какой предел ресурса попадает? Из того, что я читал онлайн, ERROR_NOT_ENOUGH_MEMORY может быть результатом приложения, поражающего любой из нескольких лимитов (объекты GDI, объекты USER, дескрипторы и т. Д.), А не обязательно память. Есть ли исчерпывающий список ограничений Windows? Есть ли способ узнать, какой предел попал? Я пробовал Google, но я не мог найти систематического обзора.

+0

GDI - мой первый порт захода. Хотя странно, что это происходит только на машине одного пользователя, вот где я начну. Он также может быть чем-то вроде количества используемых ручек и т. Д. Удачи! – 2009-09-21 14:22:29

ответ

3

Преступник в этом случае был CreateCompatibleBitmap. Очевидно, что Windows может обеспечить достаточно строгие системные ограничения на память, доступную для зависимых от устройства растровых изображений (см., Например, this mailing list discussion), даже если ваша система в противном случае имеет много памяти и много ресурсов GDI. (Эти системные ограничения, по-видимому, связаны с тем, что Windows может распределять растровые изображения, зависящие от устройства, в памяти видеокарты.)

Решение состоит в том, чтобы вместо этого использовать не соответствующие устройствам растровые изображения (DIB) (хотя они могут быть не столь хорошими представление). This KB article описывает, как выбрать оптимальный формат DIB для устройства.

Другие кандидаты в пределах ресурсов (от ответов других людей и мое собственное исследование):

  • GDI ресурсы (от этого ответа) - легко проверяются с GDIView
  • фрагментации виртуальной памяти (от этого ответа)
  • Desktop кучи - см here или here
3

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

+0

Это должно быть довольно легко проверить, попробовав одно и то же от новой перезагрузки. Можно было бы подумать, что они бы попробовали это, прежде чем публиковать его как вопрос о SO (но было что-то случилось ...) –

+0

@ T.E.D. : Перезагрузка не эффективнее, чем просто убить процесс сбоя и повторить попытку. Каждый процесс имеет свое собственное новое пространство виртуальной памяти при его создании. Обычно проблема возникает обычно в приложениях с длительным сроком действия или быстро, где есть смесь больших и маленьких кусков памяти, которые выделяются и освобождаются довольно быстро с разной продолжительностью жизни. Обычно это индикатор того, что некоторый фрагмент кода должен поддерживать список буферов для повторного использования, а не постоянного выделения и освобождения памяти. – AnthonyWJones

+0

Использование FastMM в Delphi лучше предотвращает фрагментацию виртуальной памяти. –

4

Проверьте все возможности.

Проблемы с GDI можно отслеживать с помощью бесплатной утилиты GDIView. Его единственный файл, который пользователи могут запускать без установщика.

Также установите ProcessExplorer на соответствующую машину.

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

+0

GDIView дает интересные впечатляет подробности о "объектах GDI". – Wolf

0

Мой ответ может быть немного поздно, но, с моей покойной е xperience с той же проблемой, делая все тесты, шаг за шагом, создавая DC, освобождая его, используя DIBSection вместо CompatibleBitmap, используя инструменты для утечки GDI/памяти и т. д.

В конце (LOL) я обнаружил, что :

Я переключил приоритет этих двух вызовов, тогда вся проблема была исправлена.

DeleteDC(hdc);  //do it first (always before deleting objects) 
DeleteObject(obj); 
Смежные вопросы