Как отладить зависание основного потока в приложении Delphi - PullRequest
2 голосов
/ 14 января 2010

Я написал приложение в Delphi 2007, которое иногда зависает (даже не каждую неделю, приложение работает 24/7). Похоже, что основной поток застрял. Какие есть варианты, чтобы точно определить причину этой проблемы?

Приложение написано на Delphi 2007, оно использует RemObjects, DBExpress с Firebird, OPC-связь с использованием COM.

Ответы [ 2 ]

11 голосов
/ 14 января 2010

Используя MadExcept, вы можете указать, что основной поток периодически проверяется на предмет обработки сообщений (с переменным таймаутом, значение которого вы бы указали выше, чем ваши самые длинные действия). Если основной поток зависает, вы можете получить трассировку стека.

См. Проверка заморозки основного потока ...

Я использовал это с некоторым успехом, это не удалось, только когда зависание было в драйвере (что, вероятно, следовало ожидать). Начав подозревать драйвер (для карты АЦП), я добавил сообщения трассировки до и после каждого вызова API и смог доказать, что драйвер является виновником. Обратите внимание, что будет важно немедленно записать сообщения в файл и очистить буферы для получения надежных данных журнала.

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

4 голосов
/ 15 января 2010

Для этого я использовал поток «watchdog», который проверяет, отвечает ли основная форма, и создает мини-дамп (вы можете загрузить этот дамп с помощью WinDbg, используйте map2dbg.exe для преобразования Delphi .map в .dbg).

FMainformHandle := Application.MainForm.Handle;
Result := SendMessageTimeOut( FMainformHandle, WM_NULL, 0, 0,
      SMTO_NORMAL or SMTO_ABORTIFHUNG,
      C_TIME_OUT_SECONDS * 1000, //wait 1minute
      iRes) <> 0;
if not Result then
begin
   hFile := CreateFile(PChar(Result), GENERIC_WRITE, FILE_SHARE_WRITE, nil,
         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
   try
      MiniDumpWriteDump(GetCurrentProcess, GetCurrentProcessId, hFile,
            aDumpType, nil, nil ,nil);
   finally
      FileClose(hfile);
   end;
end;

Но вы также можете использовать

jclDebug.pas:
JclCreateThreadStackTraceFromID (MainthreadId)

для этого (не требуется WinDbg и т. Д., Только JCL + Delphi .map)

3-й вариант - использовать мой новый профилировщик выборки , который имеет «средство просмотра стека процессов», так что вы можете наблюдать за стеком любого потока запущенного процесса (я использовал SysInternals Process Explorer для этого раньше , но для этого нужны файлы .dbg). Он использует .map, TD32, JDBG и т. Д. (Любую отладочную информацию Delphi) для трассировки стека.
Вы можете использовать это, когда ваше приложение зависает, чтобы исследовать стек.

Windows API (для MiniDumpWriteDump):
http://sourceforge.net/projects/jedi-apilib/files/JEDI%20Windows%20API/
WinDbg:
http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx
Map2Dbg:
http://code.google.com/p/map2dbg/
JEDI JCL:
http://jcl.delphi -jedi.org /
AsmProfiler, режим выборки: (все еще в разработке!)
http://asmprofiler.googlecode.com/files/AsmSamplingProfiler0.4.zip

...