Как мне отладить мою программу, когда она зависает?
У меня есть приложение, которое выполняет измерения каждую секунду (я запускаю его в демонстрационном режиме и генерирую случайные данные, поэтому проблема не в чтении с устройств, подключенных к последовательному порту).
Через 5 или 6 минут зависает.
я добавил
try
// entire body of procedure/function goes here
except
on E: Exception do
begin
MessageDlg('Internal coding error in <function name>()',
mtError, [mbOK], 0);
end;
end;
для каждой функции (и Application.Run() в файле проекта), но я не вижу никаких диалогов сообщений. Любая идея, как я могу проверить это?
Обновление: я полагаю, что возникнет проблема с ресурсами, будь то ОЗУ или база данных MySql, - но другие программы работают нормально, и при каждом измерении сохраняются только 5 операций с плавающей запятой и временная метка, поэтому обе из них кажутся маловероятными после такого короткого времени.
Решение: было много отличных ответов (спасибо и +1 со всех сторон), но я, наконец, получил (как и предлагалось), запустив в IDE и используя Run/Pause, чтобы увидеть, что это был постоянно увеличивающийся цикл.
Еще раз спасибо всем.
5 ответов
Я бы попробовал следующее:
Присоедините и нажмите "Приостановить" и посмотрите, где он находится, какие потоки работают, какие потоки ждут (если все из них, то у вас тупик).
Измените ваш основной метод на кучу маленьких (вы, возможно, уже сделали это), а затем замените маленькие на фиктивные / жестко закодированные значения. Это может помочь, но не обязательно идентифицировать неисправный блок.
Следите за потреблением системных ресурсов (дескрипторы, потоки и т. Д.) С помощью PerfMon или чего-то еще. Посмотрите, не хватает ли вам памяти и начните использовать жесткий диск.
Если вы используете сокеты, проверьте, установлено ли время ожидания чтения на бесконечность. Если да, то измените какое-либо значение и следите за таймаутами
В.NET возможно включить обработку всех исключений, что означает, что перед обработкой кода (как в операторе catch) среда IDE прерывается в точке исключения. Включите это в Delphi, если возможно, и посмотрите, получите ли вы.
Используйте отладчик, чтобы узнать, что делает ваше приложение, когда оно зависает.
Запустите вашу программу под отладчиком. Позвольте этому бежать, пока это не висит. Когда он зависает, переключитесь на отладчик и выберите "Debug: Break All" (или эквивалентный), чтобы заставить отладчик заморозить все потоки и получить контроль над процессом.
Теперь откройте представление Threads в отладчике и изучите следы стека каждого потока в вашей программе. Начните с основного потока, очевидно. Не забудьте просмотреть стек вызовов для нескольких вызовов, чтобы увидеть, узнаете ли вы какой-либо код. Если вы найдете трассировку стека, которая находится в середине цикла, проверьте локальные переменные, чтобы увидеть, не прошла ли переменная управления вашим циклом какое-то время за условием выхода и поместила вас в бесконечный цикл.
Если ваши трассировки стека указывают на то, что каждый поток заблокирован в ожидании какого-либо внешнего события, у вас может быть тупик потока - поток A захватывает блокировку A, затем пытается захватить блокировку B, в то время как поток B удерживает блокировку B и пытается захватить блокировку A. Если вы не используете потоки в своей программе, это менее вероятно, но все же следите за этим.
Если после просмотра следов стека потоков у вас не появится ничего странного, дайте программе поработать еще несколько секунд, затем снова откройте ее с помощью отладчика и посмотрите еще раз. Посмотрите, что отличается в следах стека.
Это должно помочь вам определить, какие части кода задействованы в вашем зависании.
Если вы не видите исключение до добавления обработчиков исключений, вы не будете создавать никаких MessageDlgs для просмотра.
Если программа зависает (а не взрывается с исключением), вы можете столкнуться с проблемой зацикливания или блокирующим вызовом, который никогда не завершится. Записывайте сообщения журнала в окно или файл (вы можете использовать OutputDebugStr), чтобы изолировать проблему в одном разделе вашего кода - по крайней мере, в теле одной функции. Вы можете увидеть проблему прямо сейчас. Если нет, вы можете использовать OutputDebugStr, точки останова и трассировки, чтобы построчно узнать, что происходит в этом разделе кода.
Сначала попробуйте отладить его в Delphi IDE. Второе: если вы не можете сделать это (на ПК клиента), попробуйте "Средство просмотра стека процессов" моего профилировщика выборки (с открытым исходным кодом): http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer
(вам нужна некоторая отладочная информация: файл.map или.jdbg). Затем посмотрите на стек ваших потоков (вероятно, основной / первый поток). Тогда вы можете опубликовать трассировку стека (если не можете найти проблему).
Если вам нужна помощь с такими вещами в приложении, для которого вы не можете использовать IDE, то что-то вроде madExcept может сильно помочь. У него есть автоматическая проверка заморозки для основного потока, и вы можете сделать так, чтобы он давал вам дамп стека, чтобы показать, что он делал, когда был заморожен. Пользователь может выбрать "убить" или "продолжить", и приложение может сказать madExcept, что оно занято, и не предупреждать, если необходимо (для выполнения длительного анализа или печати или чего-то еще).