长时间运行的方法中 Java 调试性能缓慢

Fab*_*ler 6 java eclipse debugging performance intellij-idea

更新:虽然我一年多前就问过这个问题,但仍然没有答案。出于好奇,我用 IntelliJ IDEA 重现了今天在 Eclipse 中观察到的问题。

问题

我最近正在调试一个类,其中包含执行大量操作的阻塞且长时间运行的方法。有趣的是,调试速度有时变化很大。我有一种感觉,速度与不同的调试方法(Step Into、Step Over、Step Return、Resume)相关。

用作实验的最小可重复示例

我写了一个最小的例子,可以在以下课程的帮助下重现和衡量我的感受:

java调试性能测试

测试类只是测量计数器在“长时间运行”操作中递增的频率。为了测试假设,我在调用之前设置了一个断点来停止程序longRunningOperation,然后应用不同的调试方法。

给定显示的断点,我使用不同的调试策略以不特定的顺序执行了多次重复测量(以最大限度地减少系统错误的可能性):

  1. Run:简单地执行程序(性能控制组)
  2. W/O Breakpoint:在没有断点的情况下以调试模式运行程序
  3. Resume : 在断点处暂停,然后恢复执行 (IntelliJ F9)
  4. Over:在断点处暂停,然后跳过长时间运行的方法 (IntelliJ F8)
  5. Into+Return:在断点处暂停,然后单步进入长时间运行的方法并单步退出(IntelliJ F7,然后SHIFT+F8
  6. Into+Resume:在断点处暂停,然后进入长时间运行的方法并恢复(IntelliJ F7,然后F9

实验结果

| #| 运行| 不带断点 | 简历 | 结束 | 进入+返回| 进入+简历 |
|----------|----------|----------------|-------- ---|----------|-------------|----------|
| 1 | 863342711 | 862587196 | 872204399 | 14722473 | 12550871 | 870687830 |
| 2 | 868929379 | 864245840 | 872166407 | 14139145 | 12487883 | 870626416 |
| 3 | 865544040 | 852645848 | 872988659 | 14352193 | 12459235 | 12459235 871062770 |
| 4 | 868100763 | 863198685 | 867518560 | 12261625 | 14696307 | 871365658 |
| 5 | 865157647 | 866257267 | 862671156 | 12524087 | 14620150 | 868541690 |
| 6 | 865348827 | 863449576 | 864416490 | 14410005 | 14592026 | 868784314 |
| 7 | 866957323 | 865379147 | 873324542 | 14326951 | 12648924 | 868621635 |
| 8 | 860129057 | 868993541 | 867785706 | 14434965 | 14380032 | 875011465 |
| 9 | 865961737 | 857872085 | 871137322 | 12440011 | 12262172 | 871357411 |
| 10 | 10 865517465 | 864911063 | 865109071 | 14544906 | 12391397 | 871574154 |
| | | | | | | |
| 平均 | 865498895 | 862954025 | 868932231 | 13815636 | 13308900 | 870763334 |
| 偏差| 0,00% | 0,29% | -0,40% | 98,40% | 98,46% | -0,61% |

每个调试策略执行 10 次,结果System.out.println(res)显示在相应的列中。该Mean行包含每个策略 10 次测量的平均值。该行包含与运行Deviation策略的相对偏差。结果是使用 IntelliJ IDEA 获得的,但在 Eclipse 中类似。

问题

结果表明,在调试期间使用step overstep into + step out执行长时间运行的方法比其他选项慢10 倍以上。但我无法解释为什么会发生这种情况?调试器在内部做了什么来产生这样的行为?

注意:我在 Windows 10 上使用 Java 8 和 IntelliJ IDEA 2016.2 执行了测量。


为了在您的机器上重现该行为,我已将小类放入Gist中。

Rav*_*ven 4

我仍然遇到同样的问题,我相信这并不是实现,而是一般的 Java 调试(如果这是实现的错误,IntelliJ 必须同样糟糕地实现它,并且两个 IDE 都实现它,这对我来说似乎不太可能) 。

我在 SO 上发现了这篇文章,这让我怀疑当单步执行代码时,Java 永远不会一步步离开未优化的解释字节码。当继续时,我相信它会检查它可以运行到哪一点,并以优化的方法执行此操作,从而使其速度更快。
但请注意,这只是我个人的怀疑,我没有任何事实可以证明这一点(除了这些操作的执行情况)。

然而,我确实找到了这个问题的“解决方案”。即:Run to Line.
此功能会将代码运行到光标当前所在的行。因此,它似乎与在该行中添加断点、继续执行然后再次删除断点具有相同的效果。Ctrl+R通过这种方法,人们可以通过将光标放在下一行并点击(默认快捷键)来“跳过”一行。