应用程序冻结时奇怪的调用堆栈

时间:2010-04-16 19:02:59

标签: delphi delphi-2007

我的一个应用程序中显然存在死锁问题,并开始调查EurekaLog堆栈跟踪。这是最近的一个:

Call Stack Information:
--------------------------------------------------------------------------------------------------------------------------------------
|Address |Module        |Unit                        |Class                               |Procedure/Method               |Line      |
--------------------------------------------------------------------------------------------------------------------------------------
|*Exception Thread: ID=14208; Priority=0; Class=; [Main]                                                                             |
|------------------------------------------------------------------------------------------------------------------------------------|
|7C82860C|ntdll.dll     |                            |                                    |KiFastSystemCall               |          |
|7C827D27|ntdll.dll     |                            |                                    |ZwWaitForSingleObject          |          |
|77E61C96|kernel32.dll  |                            |                                    |WaitForSingleObjectEx          |          |
|77E61C88|kernel32.dll  |                            |                                    |WaitForSingleObject            |          |
|77E61C7B|kernel32.dll  |                            |                                    |WaitForSingleObject            |          |
|004151C4|MyApp.exe     |sysutils.pas                |TMultiReadExclusiveWriteSynchronizer|WaitForWriteSignal             |16740[1]  |
|004151BC|MyApp.exe     |sysutils.pas                |TMultiReadExclusiveWriteSynchronizer|WaitForWriteSignal             |16740[1]  |
|0041522C|MyApp.exe     |sysutils.pas                |TMultiReadExclusiveWriteSynchronizer|BeginWrite                     |16818[57] |
|004323FB|MyApp.exe     |Classes.pas                 |TDataModule                         |Create                         |11357[1]  |
|004323C0|MyApp.exe     |Classes.pas                 |TDataModule                         |Create                         |11356[0]  |
|007D744D|MyApp.exe     |uRORemoteDataModule.pas     |TRORemoteDataModule                 |Create                         |163[1]    |
|007D7434|MyApp.exe     |uRORemoteDataModule.pas     |TRORemoteDataModule                 |Create                         |162[0]    |
|007DBFAB|MyApp.exe     |Sentrol_Impl.pas            |                                    |Create_Sentrol                 |85[1]     |
|00646952|MyApp.exe     |uROServer.pas               |TROInvoker                          |CustomHandleMessage            |726[11]   |
|00407BFA|MyApp.exe     |system.pas                  |TInterfacedObject                   |_AddRef                        |17972[1]  |
|00404934|MyApp.exe     |system.pas                  |TObject                             |GetInterface                   |9003[8]   |
|00407B1C|MyApp.exe     |system.pas                  |                                    |_IntfClear                     |17817[1]  |
|00404966|MyApp.exe     |system.pas                  |TObject                             |GetInterface                   |9009[14]  |
|004048E8|MyApp.exe     |system.pas                  |TObject                             |GetInterface                   |8995[0]   |
|00407BD7|MyApp.exe     |system.pas                  |TInterfacedObject                   |QueryInterface                 |17964[1]  |
|77E61680|kernel32.dll  |                            |                                    |InterlockedDecrement           |          |
|00407C10|MyApp.exe     |system.pas                  |TInterfacedObject                   |_Release                       |17977[1]  |
|00407B2C|MyApp.exe     |system.pas                  |                                    |_IntfClear                     |17824[8]  |
|004067DF|MyApp.exe     |system.pas                  |                                    |_FinalizeArray                 |15233[100]|
|00407B1C|MyApp.exe     |system.pas                  |                                    |_IntfClear                     |17817[1]  |
|00646577|MyApp.exe     |uROServer.pas               |TROClassFactoryList                 |FindClassFactoryByInterfaceName|619[17]   |
|77E6166C|kernel32.dll  |                            |                                    |InterlockedIncrement           |          |
|00407BFA|MyApp.exe     |system.pas                  |TInterfacedObject                   |_AddRef                        |17972[1]  |
|00646B72|MyApp.exe     |uROServer.pas               |TROInvoker                          |HandleMessage                  |758[1]    |
|006460C5|MyApp.exe     |uROServer.pas               |                                    |MainProcessMessage             |512[98]   |
|00645BAC|MyApp.exe     |uROServer.pas               |                                    |MainProcessMessage             |414[0]    |
|00647184|MyApp.exe     |uROServer.pas               |TROMessageDispatcher                |ProcessMessage                 |929[2]    |
|00647130|MyApp.exe     |uROServer.pas               |TROMessageDispatcher                |ProcessMessage                 |927[0]    |
|00647BCF|MyApp.exe     |uROServer.pas               |TROServer                           |IntDispatchMessage             |1328[27]  |
|00647ABC|MyApp.exe     |uROServer.pas               |TROServer                           |IntDispatchMessage             |1301[0]   |
|0064782F|MyApp.exe     |uROServer.pas               |TROServer                           |DispatchMessage                |1170[11]  |
|006477B4|MyApp.exe     |uROServer.pas               |TROServer                           |DispatchMessage                |1159[0]   |
|006477A9|MyApp.exe     |uROServer.pas               |TROServer                           |DispatchMessage                |1152[1]   |
|0064779C|MyApp.exe     |uROServer.pas               |TROServer                           |DispatchMessage                |1151[0]   |
|00659CB6|MyApp.exe     |uROLocalServer.pas          |TROLocalServer                      |SendRequest                    |57[1]     |
|00659CA4|MyApp.exe     |uROLocalServer.pas          |TROLocalServer                      |SendRequest                    |56[0]     |
|0065A009|MyApp.exe     |uROLocalChannel.pas         |TROLocalChannel                     |IntDispatch                    |99[10]    |
|005EE540|MyApp.exe     |uROClient.pas               |TROTransportChannel                 |Dispatch                       |1884[36]  |
|005EE3FC|MyApp.exe     |uROClient.pas               |TROTransportChannel                 |Dispatch                       |1848[0]   |
|005EEC8F|MyApp.exe     |uROClient.pas               |TROTransportChannel                 |Dispatch                       |2134[27]  |
|00616EC8|MyApp.exe     |PCCS_Intf.pas               |TSentrol_Proxy                      |GetNewValues                   |6585[7]   |
|007CBDB9|MyApp.exe     |ETAROConnectionForm.pas     |TROConnectionForm                   |SyncSentrolUpdateTimerTimer    |855[16]   |
|7C82ABE5|ntdll.dll     |                            |                                    |RtlTimeToTimeFields            |          |
|004D5D9C|MyApp.exe     |Controls.pas                |TControl                            |WndProc                        |5063[0]   |
|004DA05B|MyApp.exe     |Controls.pas                |TWinControl                         |WndProc                        |7304[111] |
|7C81A3AB|ntdll.dll     |                            |                                    |RtlLeaveCriticalSection        |          |
|0042659C|MyApp.exe     |Classes.pas                 |TThreadList                         |UnlockList                     |3359[1]   |
|00426598|MyApp.exe     |Classes.pas                 |TThreadList                         |UnlockList                     |3359[1]   |
|004935BC|MyApp.exe     |Graphics.pas                |                                    |FreeMemoryContexts             |5060[12]  |
|00493524|MyApp.exe     |Graphics.pas                |                                    |FreeMemoryContexts             |5048[0]   |
|004D9799|MyApp.exe     |Controls.pas                |TWinControl                         |MainWndProc                    |7076[6]   |
|004329F4|MyApp.exe     |Classes.pas                 |                                    |StdWndProc                     |11583[8]  |
|7739C09A|USER32.dll    |                            |                                    |CallNextHookEx                 |          |
|004B1343|MyApp.exe     |ExtCtrls.pas                |TTimer                              |Timer                          |2281[1]   |
|00404A30|MyApp.exe     |system.pas                  |                                    |_CallDynaInst                  |9159[1]   |
|004B1227|MyApp.exe     |ExtCtrls.pas                |TTimer                              |WndProc                        |2239[4]   |
|004329F4|MyApp.exe     |Classes.pas                 |                                    |StdWndProc                     |11583[8]  |
|7739C42C|USER32.dll    |                            |                                    |GetParent                      |          |
|7739C45C|USER32.dll    |                            |                                    |GetParent                      |          |
|773A16E0|USER32.dll    |                            |                                    |DispatchMessageA               |          |
|773A16D6|USER32.dll    |                            |                                    |DispatchMessageA               |          |
|004CC234|MyApp.exe     |Forms.pas                   |TApplication                        |ProcessMessage                 |8105[23]  |
|004CC138|MyApp.exe     |Forms.pas                   |TApplication                        |ProcessMessage                 |8082[0]   |
|004CC26E|MyApp.exe     |Forms.pas                   |TApplication                        |HandleMessage                  |8124[1]   |
|004CC264|MyApp.exe     |Forms.pas                   |TApplication                        |HandleMessage                  |8123[0]   |
|004CC563|MyApp.exe     |Forms.pas                   |TApplication                        |Run                            |8223[20]  |
|004CC4B0|MyApp.exe     |Forms.pas                   |TApplication                        |Run                            |8203[0]   |
|007F18B3|MyApp.exe     |MyApp.dpr                   |                                    |                               |215[65]   |

堆栈跟踪似乎没有问题,直到第一次TTimer调用,之后它包含一些垃圾(?),但是结尾包含似乎持有主线程的锁。

我可以信任这个堆栈跟踪吗?如果没有,是什么导致这种情况以及如何避免它?

有关基于此堆栈跟踪的死锁的任何想法?我不太明白如何创建数据模块可能会死锁..

我正在使用Delphi 2007。

编辑:我发现一个案例,其中主要线程和RemObjects创建的线程之间共享DbExpress连接。在修复了一些小问题之后,应用程序已经运行了12个多小时没有问题。我会等一两天,看看问题是否真的消失了。

4 个答案:

答案 0 :(得分:2)

我在关闭我的应用程序并在另一个线程中创建TForm或TDatamodule时遇到了同样的问题:因为应用程序正在终止,GlobalNameSpace(请参阅其他答案)被锁定(!),因此创建了我的TRORemoteDataModule另一个线程被锁定。因为我使用另一个锁等待该线程我遇到了死锁: - (。

在你的情况下,你必须看看其他线程,找到已经放置锁的那个(并且可能正在等待,否则你就不会有死锁)。我看到一个“SyncSentrolUpdateTimerTimer”:也许你在另一个线程的TDatamodule创建中做了一个TThread.Synchronize?

编辑:如果你想在死锁中查看其他线程的堆栈:

  1. 尝试Process Explorer - >过程 - >线程 - >堆栈(但您需要map2dbg.exe将Delphi .map文件转换为Microsoft .dbg文件以查看调试符号)
    http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
    http://code.google.com/p/map2dbg/
  2. 试试我的开源AsmProfiler(采样模式):它有一个“实时视图”来查看所有线程的堆栈,它使用Delphi调试符号(.map,.jdbg等),所以你不需要map2dbg .exe(顺便说一下:我制作了这个实时视图因为我经常使用Processes explorer而且每次都很烦恼使用map2dbg)
    http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer

答案 1 :(得分:1)

据我所知,EurekaLog应该是可以接受的。如果包含函数< - >地址映射的信息与可执行文件的版本不同,则堆栈跟踪可能是inccorect。

我使用JCL进行堆栈跟踪日志记录,并使用map / jdbg文件。如果更改可执行文件并保留相同的映射文件,则堆栈日志将不正确,因为函数地址将不同。所以也许唯一的原因可能是这个。您还必须区分最后一个函数调用的真实堆栈跟踪和“调用历史记录”。我使用一个调用历史记录,它也列出了记录时调用的所有函数。就像你的TTimer一样。

典型的堆栈跟踪仅包含导致最后一个函数的函数调用。另一方面,“呼叫历史”包含在特定时间范围内被调用的所有功能。如果你在主线程旁边有辅助线程(比如TTimer),它也会记录他们的动作。我忘了在JCL中如何调用它,但如果你在stRawMode中跟踪它是默认行为。

最后,我可以从堆栈跟踪中看到WaitForSingleObject被调用,最好使用INFINITE参数,因此它永远不会超时。然后,WaitForSingleObject成为信号的条件永远不会被填满。

检查“TRORemoteDataModule”及其在构造函​​数中的作用。因为它似乎只从TDataModule继承并广告了它自己的一些逻辑。这应该是导致死锁的原因。

编辑:

好的,我检查了TDataModule代码:

constructor TDataModule.Create(AOwner: TComponent);
begin
  GlobalNameSpace.BeginWrite;
  try
    CreateNew(AOwner);
    if (ClassType <> TDataModule) and not (csDesigning in ComponentState) then
    begin
      if not InitInheritedComponent(Self, TDataModule) then
        raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
      if OldCreateOrder then DoCreate;
    end;
  finally
    GlobalNameSpace.EndWrite;
  end;
end;

它使用“GlobalNameSpace”单例接口,它是这样定义和实现的:

var
  GlobalNameSpace: IReadWriteSync;

initialization
{$IFDEF MSWINDOWS}
  GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
{$ENDIF}
...

所以这是你的锁。现在有趣的是它为什么会发生?它似乎是一个标准的VCL代码。也许你可以分享一些关于应用程序正在做什么的更多信息。

此外,您还可以查找调试输出。这在课程中定义:

procedure TMultiReadExclusiveWriteSynchronizer.BeginRead;
var
  Thread: PThreadInfo;
  WasRecursive: Boolean;
  SentValue: Integer;
begin
{$IFDEF DEBUG_MREWS}
  Debug('Read enter');
{$ENDIF}
...

因此,如果定义了“DEBUG_MREWS”,您将通过“OutputDebugString”获得调试信息。它应该为这个问题注入一些亮点。对我来说,这看起来像组件初始化竞争条件。 :)

答案 2 :(得分:1)

最后一次调用是在TMultiReadExclusiveWriteSynchronizer中,但它没有显示在哪种方法中。它可能会调用Windows同步功能,并在那里被阻止。您使用的是RemObjects库吗?那里发生了一些事情。 您可以使用SysInternals Process Explorer配置为下​​载Windows符号并在进程运行时检查堆栈跟踪,如果您转换.dbg格式的Delphi符号,您将拥有整个explict调用堆栈。

答案 3 :(得分:1)

你可以在调试器下重现这个挂起吗?如果是 - 则在GlobalNameSpace的Begin / EndWrite / Read方法上设置断点。输入每个断点的高级属性并打开“Break”选项并打开“Log call stack”选项。

现在,运行您的应用程序并让它挂起。检查事件窗口。您将看到GlobalNameSpace呼叫的完整历史记录。分析一下。某处肯定会有一些错误的电话。可能是最后一个。

或者,如果您使用的是Vista及以上版本,则可以使用Wait Chain Traversal功能,但我忘了,德尔福拥有它。只需让你的应用程序挂起并看到Threads窗口:应该有阻止的原因。

在极少数情况下,挂起可能是由内存损坏引起的。例如,坏代码可能会擦除/损坏“Free”/“Busy”标志,因此第一个尝试获取锁定的代码将永远等待,因为没有人释放锁定(因为它没有被锁定,它被损坏了。)