为什么条件调试如此缓慢?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (24)

我发现,当我使用条件断点进行调试时,执行速度大大减慢。我想了解原因。到底是什么原因导致执行如此缓慢?我知道添加了一个条件,但是如果我手动添加条件,我不会减慢执行速度。

有以下代码。假设添加了一个条件断点a=i...。将条件设置为i==10000。

public class Main {

    public static void main(String[] args) {
        int a = 0;

        for (int i = 0; i<100000; i++) {
                a = i;  //put breakpoint here (if i == 10000)
        }
        System.out.println("Done! a=" + a);
    }
}

然后

public class Main {

    public static void main(String[] args) {
        int a = 0;

        for (int i = 0; i<100000; i++) {
            if (i == 10000)
                a = i; //put a NON-conditional breakpoint here
            else a = i;
        }
        System.out.println("Done! a=" + a);
    }
}

为什么两者的运行时间有如此巨大的不同?为什么第一个要慢得多?

调试环境是Linux(Ubuntu)上Oracle-JDK-8。我在Eclipse和IntelliJ上得到了同样的结果。


结果

我在多个IDE上运行了第一个案例,以查看是否存在差异。以下是结果

IntelliJ:

~9秒到达断点

~90秒到达完成(包括初始的9秒)

Eclipse:

~9秒到达断点

~90秒到达完成(包括初始的9秒)

NetBeans:

~12秒到达断点

~190秒完成(包括初始12秒)

所以IntelliJ和Eclipse差不多,但是NetBeans要慢得多。

第二个例子几乎是在所有IDE上瞬间运行的

提问于
用户回答回答于

我还没有实现IDE、调试器或JVM,所以我不能确定事情是否与我在这里解释的完全一样。

但是。当代码与调试器一起运行时,JVM会解释代码,直到它遇到断点为止。然后停止并调用调试器(IDE)。

JVM不支持条件断点,因此IDE使用“hack”来完成此功能。IDE只添加一个普通断点。每次命中断点时,IDE都会在通知用户之前对表达式本身进行评估,如果计算值为false,则会发送“继续”命令。

现在来看看你的例子。在第二个示例中,JVM只执行一次这样的调用。在第一个例子中,这是100000次。每次JVM调用调试器并等待它解释条件并发送到JVM命令“继续”时(就像调试代码时可以手动执行的一样)。显然100000>1,所以这个过程需要时间。

用户回答回答于

条件断点依赖于条件的解释性(!)计算,只要命中断点的位置,就会执行。

命中断点是快速的:执行的顺序流被中断,例如,用触发中断的代码替换该位置的指令。但是,条件的计算必须从内存中获取变量的值并计算结果,这与表达式在编译代码中计算的方式不同。预计会有相当大的减速。

虽然编译后的表达式会产生机器指令(在Java中,至少在JIT编译之后),但解释表达式基于抽象语法树(数据结构),例如Equals( Variable( "i" ), Literal( 10000 ))以及在该数据结构上下降的代码,获取值(“i”)并计算操作(“==”)。

扫码关注云+社区