【问题标题】:Why is debugging with some exceptions enabled much slower?为什么启用某些异常的调试要慢得多?
【发布时间】:2019-01-10 05:17:47
【问题描述】:

考虑以下代码:

public class JMain {
    private final static int forLength = 6;

    private static void returnFromFor(int breakAt) {
        try {
            for (int j = 0; j < forLength; j++) {
                if (j == breakAt) {
                    throw new Throwable("break");
                }
            }
        } catch (Throwable ignored) {
        }
    }

    public static void main(String args[]) {
        long start = System.currentTimeMillis();
        int iterations = 100000;
        for (int i = 0; i < iterations; i++) {
            returnFromFor(i % forLength);
        }

        long end = System.currentTimeMillis();
        System.out.println(((Long) (end - start)).toString() + " ms");
    }
}

当我在 IntelliJ IDEA 调试器中运行此代码并为 java.lang.IllegalArgumentException 启用异常断点时,它在我的计算机上运行非常慢,大约 1800 毫秒。当我在没有异常断点或为java.lang.UnsupportedOperationException 启用断点的情况下运行它时,它的速度大约快了 10 倍。

我的问题是:

  • 为什么使用IllegalArgumentException 调试比使用UnsupportedOperationException 慢很多?

  • 是 JVM 调试器还是 IntelliJ 导致的减速?

我正在运行的系统是:

  • Windows x64
  • IntelliJ IDEA Ultimate 2018.2
  • JRE:1.8.0_152-release-1248-b8 amd64

注意:上面的代码演示了我在使用复杂的 Scala 时遇到的问题。如果有人对更自然的 Scala 代码演示感兴趣,那就来吧:

object Main extends App {

  val forLength = 6
  def returnFromFor(breakAt: Int): Unit = {
    for (j <- 0 until forLength) {
      if (j == breakAt) return
    }
  }

  val start = System.currentTimeMillis()
  val iterations = 100000
  for (i <- 0 until iterations) {
    returnFromFor(i%forLength)
  }
  val end = System.currentTimeMillis()
  println(s"Duration ${end-start} ms")

}

【问题讨论】:

  • 如果你使用调试器simple print hello world,它仍然很慢吗?如果有,你的操作系统是什么?
  • @snr 这是 Winx64 - 在问题中添加了系统配置。至于简单的printf demo,恐怕看不懂。除非我启用异常断点,否则没有性能差异。当我启用它们时,没有抛出异常时没有区别。
  • 不,我的意思是当您启用简单断点System.out.println("test");。调试器还慢吗??
  • 启用代码断点对性能没有任何影响。它只是启用一些异常断点。

标签: java scala debugging intellij-idea jvm


【解决方案1】:

IDEA 在目标异常类被加载之前不会设置异常断点。

UnsupportedOperationException 在程序的生命周期内永远不会被加载。这就是为什么程序运行得和没有断点一样快的原因。

IllegalArgumentException 是更流行的类,它在 JVM 启动期间加载到 JDK 类库中的某个位置。在这种情况下,确实设置了异常断点,以便调试器接收有关您程序中抛出的所有异常的通知。

【讨论】:

  • 我认为这完美地解释了我所看到的一切。我仍然很好奇 - 是否有可能以某种方式说服我 IllegalArgumentException 真的加载了,而另一个没有?我尝试在IllegalArgumentException 的所有构造函数上放置断点,但它们没有触发。我想是否可以加载一个类而不在其上执行构造函数。这可以以某种方式检测到吗?还是在调试器附加到进程之前就加载了这个类?
  • 我确认在我的程序早期使用throw new java.lang.UnsupportedOperationException() 会导致性能下降,正如您所预测的那样,当相应的异常断点启用时。
  • @Suma Run java -verbose:class。完全可以在不创建任何实例的情况下加载一个类。
  • @apangig 我做到了。令我惊讶的是,IllegalArgumentExceptionUnsupportedOperationException 在应用程序初始化期间都被列出了,这超出了我的范围。
猜你喜欢
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
  • 2011-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-25
  • 2019-06-17
相关资源
最近更新 更多