长期运行方法中的Java调试速度慢

时间:2015-03-02 10:25:47

标签: java eclipse performance debugging intellij-idea

  

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

问题

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

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

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

java debugging performance testing

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

鉴于显示断点,我使用不同的调试策略以无特定顺序(以最小化系统错误的可能性)执行多次重复测量:

  1. 运行:只需执行程序(性能控制组)
  2. W / O断点:在没有断点的情况下以调试模式运行程序
  3. 恢复:在断点处停止,然后恢复执行(IntelliJ F9
  4. 结束:在断点处停止,然后跳过长时间运行的方法(IntelliJ F8
  5. 进入+返回:在断点处停止,然后进入长时间运行的方法并退出(IntelliJ F7 < / kbd>,然后 SHIFT + F8
  6. 进入+恢复:在断点处停止,然后进入长时间运行的方法和恢复(IntelliJ F7 ,然后 F9
  7. 实验结果

    | #         | 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行包含与运行策略的相对偏差。结果是使用IntelliJ IDEA获得的,但在Eclipse中类似。

    问题

    结果表明,在调试过程中使用步骤步进+步出执行长时间运行的方法超过 10x慢与其他选项相比。但是我无法解释为什么会发生这种情况?调试器内部做了什么来产生这种行为?

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


    要重现您机器上的行为,我已将小班放入Gist

2 个答案:

答案 0 :(得分:1)

我也观察到了这一点。在eclipse中必须是一个糟糕的跨越实现。我通常在复杂方法之后设置断点,然后使用恢复跳转,而不是使用跳过,因为恢复通常更快。

由于跳过可以在内部进行编程,就像设置断点并按恢复一样,这可能只是以不好的方式实现。

编辑:刚刚意识到它不一样。当您按下resume并跳转到断点时,您可能会停在由其他线程触发的断点处。

答案 1 :(得分:1)

我仍然遇到相同的问题,我认为它的实现方式不像一般的Java调试(如果是实现方式的错误,IntelliJ必须同样严重地实现它,并且两个IDE都很难实现它,这似乎不太可能给我)。

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

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