java - 长时间运行的方法中的 Java 调试性能较慢

标签 java eclipse performance debugging intellij-idea

Update: While I asked this question over a year ago, there is still no answer. Out of curiosity, I reproduced the problem I observed with Eclipse today with IntelliJ IDEA.

问题

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

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

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

java debugging performance testing

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

鉴于显示的断点,我使用不同的调试策略以不特定的顺序执行了几次重复测量(以尽量减少系统错误的可能性):

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

实验结果

| #         | Run       | W/O Breakpoint | Resume    | Over     | Into+Return | Into+Resume |
|-----------|-----------|----------------|-----------|----------|-------------|-------------|
| 1         | 863342711 | 862587196      | 872204399 | 14722473 | 12550871    | 870687830   |
| 2         | 868929379 | 864245840      | 872166407 | 14139145 | 12487883    | 870626416   |
| 3         | 865544040 | 852645848      | 872988659 | 14352193 | 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        | 865517465 | 864911063      | 865109071 | 14544906 | 12391397    | 871574154   |
|           |           |                |           |          |             |             |
| Mean      | 865498895 | 862954025      | 868932231 | 13815636 | 13308900    | 870763334   |
| Deviation | 0,00%     | 0,29%          | -0,40%    | 98,40%   | 98,46%      | -0,61%      |

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

问题

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

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


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

最佳答案

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

我找到了 this post在这里,这让我怀疑在单步执行代码时,Java 永远不会一步一步地离开未优化的解释字节码。当继续时,我相信它会检查它可以运行到哪个点,并以优化的方法执行此操作,从而使它更快。
但请注意,这只是我个人的猜测,我没有任何事实可以证明这一点(除了那些操作的性能)。

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

关于java - 长时间运行的方法中的 Java 调试性能较慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28807452/

相关文章:

java - Maven 网络资源问题

javascript - 在 javascript 中实现 if then else if else 堆栈的更简单方法是什么

java - 就性能而言,: foo. setVisibility(View.GONE) 和parent.removeView(foo) 哪个更好?

performance - 如何分析golang的内存?

java - 自动将 aw 转换为 swing

java - 使用 session 防止表单垃圾邮件

java - 从 Eclipse 返回已删除的项目

java - 在 Eclipse 中拼错方法名称后如何恢复自动完成?

java - 我可以模板化 h :dataTable?

java - Smack 抛出 "Exception in thread "Smack 数据包读取器(0 )"java.lang.NoSuchMethodError: org.jivesoftware.smack.util.StringUtils.parseDate"