当我调试循环内出错的东西时,比如在第 600 次迭代时,必须对每个循环进行中断可能会很痛苦。因此,我尝试设置一个条件断点,仅在 I = 600 时才中断。这可行,但现在几乎需要一整分钟才能到达该点,而在此之前几乎是瞬时的。这是怎么回事,有什么办法可以解决吗?
当您遇到断点时,Windows 会停止进程并通知调试器。它必须切换上下文,评估条件,决定不,您不想收到有关它的通知,重新启动进程并切换回来。这可能需要很多处理器周期。如果您在紧密循环中执行此操作,则所需的处理器周期将比循环的一次迭代多几个数量级。
如果您愿意稍微修改一下代码,有一种方法可以在不产生所有这些开销的情况下执行条件断点。
if <condition here> then
asm int 3 end;
这是一个简单的汇编指令,手动向操作系统发送断点通知。现在您可以在程序内评估您的状况,而无需切换上下文。只要确保用完后再次将其取出即可。如果 int 3 在未连接到调试器的程序中发生错误,则会引发异常。
它会减慢速度,因为每次您到达该点时,它都必须检查您的状况。
我倾向于做的是临时创建另一个像这样的变量(在 C 中,但在 Delphi 中应该可行)。
int xyzzynum = 600;
while (true) {
doSomething();
if (--xyzzynum == 0)
xyzzynum = xyzzynum;
}
然后我在
"xyzzynum = xyzzynum;"
行放置一个非条件断点。
程序全速运行,直到循环了 600 次,因为调试器只是执行正常的断点中断,而不是每次都检查条件。
您可以使条件变得尽可能复杂。
根据 Mason 的回答,您可以仅在程序是使用定义的调试条件构建的情况下编译 int 3 汇编器:
{$ifdef debug}
{$message warn 'debug breakpoint present in code'}
if <condition here> then
asm int 3 end;
{$endif}
所以,当你在ide中调试时,你的项目选项中有调试条件。当您为客户构建最终产品时(使用构建脚本?),您不会包含该符号,因此它不会被编译。
我还包含了 $message 编译器指令,因此您在编译时会看到一条警告,让您知道代码仍然存在。如果您在使用 int 3 的任何地方都这样做,您将获得一个很好的位置列表,您可以双击该列表直接进入有问题的代码。
N@
Mason的解释非常好。
通过测试您在调试器下运行,可以使他的代码变得更安全一点:
if (DebugHook <> 0) and <your specific condition here> then
asm int 3 end;
当应用程序正常运行时,这不会执行任何操作;如果应用程序在调试器下运行(无论是从 IDE 启动还是附加到调试器),则会停止。如果您不在调试器下,则使用布尔快捷方式
<your specific condition here>
甚至不会被评估。
可以加速这一过程的一种方法是,将条件后跟一个没有副作用的操作直接放入代码中,并在该操作上中断。完成后请记住删除条件和操作。