当我在一个循环中调试一些出错的东西时,比如在第 600 次迭代时,每次都必须中断可能会很痛苦。因此,我尝试设置一个条件断点,仅在 I = 600 时才中断。这可行,但现在需要将近一分钟才能到达该点,而在此之前几乎是瞬时的。这是怎么回事,有什么办法可以解决吗?
6 回答
当您遇到断点时,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@
梅森的解释很好。通过测试您在调试器下运行的
代码,可以使他的代码更加安全:
if (DebugHook <> 0) and <your specific condition here> then
asm int 3 end;
当应用程序正常运行时,这不会做任何事情,如果它在调试器下运行(无论是从 IDE 启动还是附加到调试器),它将停止。如果您不在调试器下,甚至不会评估
布尔快捷方式。<your specific condition here>
任何调试器中的条件断点(我只是在这里推测)都需要每次遇到断点时进程在程序和调试器之间来回翻转。这个过程很耗时,但我认为您无能为力。
通常条件断点通过在代码中插入适当的中断指令然后检查您指定的条件来工作。它将在每次迭代时进行检查,并且很可能是检查的实现方式导致了延迟,因为调试器不太可能编译并将完整的检查和断点代码插入现有代码中。
您可能能够加速这一点的一种方法是,如果您将条件后跟一个没有副作用的操作直接放入代码中并在该操作上中断。完成后请记住删除条件和操作。