Охота на EOutOfResources - PullRequest
       15

Охота на EOutOfResources

10 голосов
/ 02 февраля 2010

Вопрос:

Есть ли простой способ получить список типов ресурсов, которые просочились в работающее приложение? IOW путем подключения к приложению?

Я знаю, что memproof может это сделать, но он настолько тормозит, что приложение не будет работать даже минуту. Большинство лайков менеджера задач могут показывать номер, но не его тип.

Это не проблема, что сама проверка является катастрофической (останавливает процесс приложения), так как я могу проверить с помощью taskmgr, подхожу ли я близко (или, по крайней мере, надеюсь)

Также приветствуются любые другие идеи по поиску утечек ресурсов (не памяти).

Справка:

У меня есть приложение Delphi 7/2006/2009 (компилируется со всеми тремя), и примерно через несколько недель оно начинает вести себя забавно. Однако только в одном из мест, где он работает, в нескольких других системах он работает до тех пор, пока не отключится питание.

Я пытался вставить некоторый отладочный код, чтобы сузить проблему. и обнаружил, что исключением является EOutofResources при сохранении файла. (сохранение файла может происходить тысячи раз в день).

Я пытался выяснить утечки памяти (с помощью fastmm), но, поскольку поток данных довольно высок (60 МБ / с от гигабитной промышленной камеры), я могу исключить только «ползучие» утечки памяти с помощью fastmm, а не быстрых вспышек утечки памяти, которые истощают память примерно в то время, когда это происходит. Если что-то идет не так, приложение заполняет память менее чем за полминуты.,

Основными подозреваемыми являются файловые дескрипторы, которые каким-то образом остаются при некоторых ошибках, и TMetafiles (которые передаются в эти файлы). Незначительные подозреваемые - VST, popupmenu и tframes

Обновления:

Еще один возможный совет: в течение двух лет он работал нормально с D7, и теперь проблемы с Turbo Explorer (который я использую для стабильных проектов, не преобразованных в D2009).

Пол-Ян: поскольку это происходит только раз в неделю (а это может происходить ночью), сбор информации происходит медленно. Именно поэтому я задаю этот вопрос, нужно объединить вещи для того времени, когда я буду там в четверг. Короче говоря: нет, я не знаю, уверен на 100%. Я собираюсь принести всю коллекцию Systemtools, чтобы посмотреть, смогу ли я что-нибудь найти (потому что тогда она будет работать несколько дней). Также есть вероятность, что я вижу открытые файлы. (возможно, стоит попытаться найти mingw lsof и запланировать его)

Но приложение видит очень мало действий с графическим интерфейсом (это приложение для проверки машинного зрения), за исключением обновления экрана +/- 15 / s, которое представляет собой tbitmap stretchdraw + tmetafile, но я получаю эту ошибку при сохранении на диск (TFileStream) вероятно действительно исчерпаны. Однако в том же потоке TMetafile также сохраняется в потоковом режиме, чего у более поздних приложений больше нет, и они могут работать в течение нескольких месяцев.

------------------- ОБНОВЛЕНИЕ

Я искал, искал и искал, и мне удалось воспроизвести проблемы в пробирке два или три раза. Проблемы возникали, когда значение memusage составляло +/- 256 МБ (в системах 2 ГБ), объекты пользователя 200, объекты gdi 500, ни один файл не был открыт больше, чем ожидалось).

Это на самом деле не исключение. Я замечаю, что я пропускаю небольшое количество дескрипторов, возможно, из-за перерисовки кадров (что-то в VCL, похоже, пропускает HPalette), но я подозреваю, что основная причина - это другая проблема. Я повторно использую TMetafile, и .clear его между ними. Я думаю, что очистка метафайла на самом деле (всегда?) Не изменяет размер ресурса, в конечном итоге каждый метафайл во всем пуле tmetafile в максимальном размере, и с 20-40+ tmetafiles (которые могут быть несколько 100ks каждый) это попадет на рабочий стол предел кучи.

Это теория, но я попытаюсь проверить это, установив ограничение рабочего стола на 10 МБ для клиентов, но пройдет несколько недель, прежде чем я получу подтверждение, если это что-то изменит. Эта теория также подтверждает, почему эта машина особенная (возможно, эта машина в среднем имеет несколько большие метафайлы). Иногда может помочь освобождение и воссоздание tmetafile в пуле.

К счастью, все эти проблемы (tmetafile и reparenting) уже разработаны в новых поколениях приложений.

Из-за особых обстоятельств (а также из-за того, что у меня очень ограниченные тестовые окна), это будет какое-то время, но я решил пока принять кучи рабочего стола в качестве примера (хотя материал GDILeaks также был несколько полезно).

Другое дело, что аудит выявил использование GDI-типов в потоке (хотя сохранял только tmetafiles (которые не использовались или не подключались иным образом) в потоки.

------------- Обновление 2.

Увеличение лимита рабочего стола, казалось, лишь незначительно увеличивало время до возникновения проблемы.

К сожалению, я не смогу продолжить это, так как машины были обновлены до более новой версии платформы, у которой нет проблемы.

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

  • Я больше не меняю экраны, перерисовывая кадры. Теперь я работаю с формами, которые я скрываю и показываю. Я изменил это, так как у меня также были очень редкие сбои или исключения (которые могли быть удалены) из-за этого. Все сбои происходили во время работы с графическим интерфейсом, а не спонтанно, как основная проблема
  • Подпрограмма, в которой произошел сбой, касалась TMetafile. TMetafile был разработан и заменен более простым форматом собственного производства. (в основном массивы с вершинами Opengl)
  • Рисование больше не происходило с tbitmap с растянутым поверх него оверлеем tmetafile, но с использованием OpenGL.

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

Обновлен ноябрь 2012 после некоторого обсуждения в частной почте: в ретроспективе следующим шагом было бы добавление счетчика к объектам метафайлов и просто повторное создание их при каждом использовании x * 1000 или около того, и посмотреть, это что-то меняет. Если у вас есть похожие проблемы, попробуйте посмотреть, можете ли вы регулярно уничтожать и повторно инициализировать долгоживущие ресурсы, которые динамически выделяются.

Ответы [ 7 ]

11 голосов
/ 02 февраля 2010

Существует тонкий шанс того, что ошибка вводит в заблуждение. VCL наивно сообщает EOutOfResources , если он не может получить DC для окна (см. TWinControl.GetDeviceContext в Controls.pas ).

Я говорю «наивно», потому что есть другие причины, по которым GetDC () может возвращать дескриптор NULL, а VCL должен сообщать об ошибке ОС, а не предполагать состояние нехватки ресурсов. (требуется проверка версии Windows, чтобы это было надежно возможным, но VCL мог и должен принять это тоже).

У меня была ситуация, когда я получал ошибку EOutOfResources из-за того, что дескриптор окна стал недействительным. Как только я обнаружил истинную проблему, найти причину и устранить ее было просто, но я потратил много, много часов, пытаясь найти несуществующую утечку ресурса.

Если возможно, я бы изучил трассировку стека, ведущую к этому исключению - если она исходит от TWinControl.GetDeviceContext , тогда проблема может быть не в том, что вы думаете (невозможно сказать, что это может быть, конечно, Но устранение невозможного всегда является первым шагом к поиску решения, каким бы невероятным оно ни было).

6 голосов
/ 02 февраля 2010

Если это утечки GDI, вы можете взглянуть на MSDN Magazine January 2003 , в котором используется инструмент GDILeaks . Другие инструменты: GDIObj или GDIView . Также см. здесь .

Другим источником EOutOfResources может быть заполнение Desktop Heap . У меня была эта проблема на загруженных терминальных серверах с большими экранами.

Если есть много файловых дескрипторов, которые вы пропускаете, вы можете проверить Process Explorer, взглянуть на дескрипторы открытых файлов вашего процесса и увидеть какие-нибудь необычные. Или используйте WinDbg с командой ! Htrace .

2 голосов
/ 08 августа 2013

Я столкнулся с этой проблемой до . Из того, что я смог сказать, Delphi может выдавать EOutOfResources в любое время, когда Windows API возвращает ERROR_NOT_ENOUGH_MEMORY, и (как обсуждают другие ответы здесь) Windows может возвращать ERROR_NOT_ENOUGH_MEMORY для различных условий.

В моем случае EOutOfResources был вызван TBitmap - в частности, вызов TBitmap к CreateCompatibleBitmap , который он использует со стандартным PixelFormat pfDevice. Очевидно, Windows может применять довольно строгие системные ограничения на объем памяти, доступной для зависящих от устройства растровых изображений (см., Например, это обсуждение ), даже если ваша система в противном случае имеет много памяти и много ресурсов GDI. (Эти общесистемные ограничения, очевидно, обусловлены тем, что Windows может выделять зависящие от устройства растровые изображения в памяти видеокарты.)

Решение состоит в том, чтобы просто использовать независимые от устройства растровые изображения (DIB) вместо этого (хотя они могут не обеспечивать столь же хорошую производительность). Чтобы сделать это в Delphi, установите TBitmap.PixelFormat в любое значение, отличное от pfDevice. В этой статье базы знаний описывается, как выбрать оптимальный формат DIB для устройства, хотя я обычно просто использую pf32Bit вместо того, чтобы пытаться определить оптимальный формат для каждого из мониторов, на которых отображается приложение.

2 голосов
/ 02 февраля 2010

"Я попытался вставить некоторый отладочный код, чтобы сузить проблему. Я обнаружил, что исключение составляет EOutofResources при сохранении файла. (Сохранение файла может происходить тысячи раз в день)."

Я снимаю в темноте, но может ли быть так, что вы используете Windows API для (GetTempFileName) создания временного файла, и вы удаляете некоторые индексы файловой системы или забыли закрыть дескриптор файла?

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

2 голосов
/ 02 февраля 2010

В большинстве случаев я видел EOutOfResources , это была какая-то утечка ручки.

Вы пробовали что-то вроде MadExcept ?

- Йерун

0 голосов
/ 23 июля 2010

В настоящее время у меня возникает эта проблема в программном обеспечении, которое явно не пропускает никаких дескрипторов в моем собственном коде, поэтому, если есть утечки, они могут происходить в исходном коде компонента или в самом исходном коде VCL.

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

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

Во-вторых, AQTime содержит множество инструментов, которые могут вам помочь, включая профилировщик ресурсов, который может хранить связи между тем, где находится код, создавший ресурсы, и тем, как он был вызван, а также подсчетами общего числа дескрипторов. Он может захватывать результаты MID RUN, и поэтому он не ограничивается обнаружением неосвобожденных ресурсов после выхода. Итак, запустите AQTime, выполните захват результатов в середине, подождите несколько часов и снова запишите, и у вас должно быть два момента времени для сравнения подсчета дескрипторов. На всякий случай это очевидная вещь. Но, как мудро указывает Делтикс, этот класс исключений возникает в тех случаях, когда он, вероятно, не должен был быть.

0 голосов
/ 02 февраля 2010

Также попробуйте проверить количество дескрипторов для приложения с помощью Process Explorer из SysInternals. Утечки ручек могут быть очень опасными, и они со временем накапливаются медленно.

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