当程序卡住时,我该如何调试它?

3

我有一个应用程序,每秒钟进行一次测量(我正在演示模式下运行它并生成随机数据,因此问题不在于从连接到串行端口的设备中读取数据)。

大约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()),但我没有看到任何消息对话框。有什么想法如何测试这个?
更新:我会猜测这是一个资源问题,无论是RAM还是MySql数据库 - 但其他程序都在正常运行,每次测量只保存5个浮点数和时间戳,所以在这么短的时间内两者都不太可能。
解决方案:有许多很好的答案(感谢并+1所有人),但最终我通过运行IDE并使用运行/暂停来查看它是一个不断增加的循环(如建议的那样)。
再次感谢大家。
5个回答

5
我建议您尝试以下方法:
  1. 附加并点击暂停,查看程序当前运行到哪一步,有哪些线程在运行,哪些线程在等待(如果所有线程都在等待,则可能出现死锁)。

  2. 将您的主要方法重构为许多小方法(您可能已经这样做了),然后用虚拟/硬编码值替换小方法。这可能有所帮助,但不一定能确定错误块。

  3. 使用PerfMon或其他工具观察系统资源消耗(句柄、线程等)。查看是否内存不足并开始使用硬盘。

  4. 如果您正在使用套接字,请检查读取超时是否设置为无限期。如果是,请更改为某个值,并观察是否出现超时。

  5. 在.NET中,可以启用处理所有异常的功能,这意味着在代码处理异常之前(如在catch语句中),IDE会在异常点处中断。如果可能的话,请在Delphi中启用此功能,并查看是否有任何异常。


谢谢,一些好的建议(+1)。(请查看问题的轻微更新) - Mawg says reinstate Monica
不使用套接字(+1)。6个线程。物理内存正常,但该进程的CPU使用率达到48%,总体上接近100%。我每秒更新一次字符串网格和图表,但由于数据是添加在末尾的,所以这不应该是问题(我认为)。 - Mawg says reinstate Monica
1
通常情况下,如果任务不需要进行计算密集型操作,它不会占用100%的CPU。可能存在轻微的活锁情况,即线程没有被阻塞,但仍然相互依赖并试图通过向彼此发出信号来继续执行,但仍然无法完成。尽管这种情况很少见。 - Schultz9999
1
顺便提一下,如果线程使用某种无限超时的等待路由相互等待,请尝试将其设置为小于该值并捕获超时。 - Schultz9999
1
同时我希望你没有使用自旋锁(例如 while(boolContinue != true) {}),因为那样很容易导致 CPU 占用率达到 100%。 - Schultz9999

5
使用调试器可以找出应用程序在出现挂起时正在进行的操作。
在调试器下运行程序,让它一直运行直到挂起。当它挂起后,切换到调试器并选择“调试:中断所有”(或相应选项)来使调试器冻结所有线程并控制进程。
现在在调试器中打开“线程”视图,并检查程序中每个线程的堆栈跟踪。首先从主线程开始。务必要向后查看几个函数调用以查看是否能识别出代码中的任何问题。如果发现一个堆栈跟踪正处于循环中间,请检查本地变量以查看您的循环控制变量是否已经超过了退出条件,将您置于无限循环中。
如果您的堆栈跟踪表明每个线程都被阻塞等待某个外部事件,则可能存在线程死锁 - 线程A获取锁A,然后尝试获取锁B,而线程B持有锁B并尝试获取锁A。如果您的程序中没有使用线程,则这种情况不太可能,但仍然要注意。
如果通过查看线程的堆栈跟踪仍未发现异常情况,请让程序再运行几秒钟,然后再次使用调试器中断程序并查看周围环境。查看堆栈跟踪中的不同之处。
这应该有助于确定哪些代码段参与了程序挂起。

+1 感谢,我会去做的。我怀疑这可能不是线程争用问题,而更像是一个无限循环,但还是感谢您的反馈。 - Mawg says reinstate Monica

1

如果在添加异常处理程序之前没有看到异常,那么就不会产生任何MessageDlgs可供查看。

如果程序挂起(而不是因为异常而崩溃),则可能存在循环问题,或者可能存在某些阻塞调用永远无法完成。编写日志消息以将问题隔离到代码的一个部分,可以将其写入窗口或文件(可以使用OutputDebugStr)。您可能会立即看到问题。如果没有,则可以使用OutputDebugStr、断点和跟踪逐行了解该代码段中发生的情况。


如果在添加异常处理程序之前没有看到异常,你就不会产生MessageDlgs来查看...d'oh!! (+1) 是的,可能是循环...我正在每秒更新一个字符串网格和图表,但由于数据是在末尾添加的,所以应该不是问题(我想),但我会进行调查。(跟踪?) - Mawg says reinstate Monica
我会先记录日志以找出问题所在,然后在该部分开头设置断点。如果必须跟踪5分钟的正常程序操作,可能需要花费数天时间! - Larry Lustig

1

首先:尝试在Delphi IDE中进行调试。 其次:如果您无法在客户PC上进行调试,请尝试使用我的(开源)采样分析器的“进程堆栈查看器”: http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer
(您需要一些调试信息:.map或.jdbg文件) 然后查看您的线程堆栈(可能是主/第一个线程)。如果您找不到问题,可以在此处发布堆栈跟踪。


0
如果您在无法使用IDE的应用程序中需要此类帮助,那么 madExcept 等工具可以帮助很多。它有一个主线程的自动冻结检查器,并且可以让您获得堆栈转储来显示它被冻结时正在执行什么操作。用户可以选择继续或结束,应用程序可以告诉 madExcept 它正忙并且在适当时不要发出警报(例如进行长时间分析、打印等)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接