Java 为什么这个循环多次的程序在循环后有一个“println”时要花费时间?

Java 为什么这个循环多次的程序在循环后有一个“println”时要花费时间?,java,eclipse,loops,println,Java,Eclipse,Loops,Println,下面是我正在尝试的小代码。这个程序需要很长的时间来执行。在运行时,如果我试图通过eclipse中的terminate按钮终止它,它将返回terminate Failed。我可以使用kill-9从终端杀死它 但是,当我没有在程序的最后一行打印变量结果时(请检查代码的注释部分),程序立即退出 我想知道: 打印结果值时,为什么要花时间执行请注意,如果我不打印值,相同的循环会立即结束。 为什么eclipse不能终止程序 更新1: JVM似乎在运行时(而不是在编译时)优化代码。这很有帮助 更新2: 当我打

下面是我正在尝试的小代码。这个程序需要很长的时间来执行。在运行时,如果我试图通过eclipse中的terminate按钮终止它,它将返回
terminate Failed
。我可以使用
kill-9
从终端杀死它

但是,当我没有在程序的最后一行打印变量结果时(请检查代码的注释部分),程序立即退出

我想知道:

  • 打印结果值时,为什么要花时间执行
    请注意,如果我不打印
    ,相同的循环会立即结束。

  • 为什么eclipse不能终止程序

  • 更新1: JVM似乎在运行时(而不是在编译时)优化代码。这很有帮助

    更新2: 当我打印
    value
    的值时,
    jstack
    不起作用。只有
    jstack-F
    在工作。有什么可能的原因吗

        public class TestClient {
    
            private static void loop() {
                long value =0;
    
                for (int j = 0; j < 50000; j++) {
                    for (int i = 0; i < 100000000; i++) {
                        value += 1;
                    }
                }
                //When the value is being printed, the program 
                //is taking time to complete
                System.out.println("Done "+ value);
    
                //When the value is NOT being printed, the program 
                //completes immediately
                //System.out.println("Done ");
            }
    
            public static void main(String[] args) {
                loop();
            }
        }
    
    公共类TestClient{
    私有静态void循环(){
    长值=0;
    对于(int j=0;j<50000;j++){
    对于(int i=0;i<100000000;i++){
    数值+=1;
    }
    }
    //打印值时,程序
    //这需要时间来完成
    系统输出打印项次(“完成”+值);
    //当不打印该值时,程序
    //立即完成
    //系统输出打印项次(“完成”);
    }
    公共静态void main(字符串[]args){
    loop();
    }
    }
    
    这是因为编译器/JVM优化。打印结果时,计算和编译器将保持循环


    另一方面,当您不使用循环中的任何内容时,编译器/JVM将删除循环。

    我怀疑当aou不打印结果时,编译器会注意到,
    value
    的值从未使用过,因此能够作为优化删除整个循环

    因此,如果没有
    println
    ,您根本就不会循环,程序只会在打印值时立即退出,而您正在执行所有5000000000000次迭代,这可能会有点长

    作为一个建议,试试看

    public class TestClient {
    public static long loop() {
        long value =0;
    
        for (int j = 0; j < 50000; j++) {
            for (int i = 0; i < 100000000; i++) {
                value += 1;
            }
        }
        return value   
     }
    
    public static void main(String[] args) {
        // this might also take rather long
        loop();
        // as well as this
        // System.out.println(loop());
    }
    }
    
    公共类TestClient{
    公共静态长循环(){
    长值=0;
    对于(int j=0;j<50000;j++){
    对于(int i=0;i<100000000;i++){
    数值+=1;
    }
    }
    返回值
    }
    公共静态void main(字符串[]args){
    //这也可能需要相当长的时间
    loop();
    //还有这个
    //System.out.println(loop());
    }
    }
    

    在这里,编译器将无法优化
    loop()
    中的循环,因为它可能从其他各种类调用,因此它将在所有情况下执行。

    基本上,JVM非常智能。它可以感知您是否在使用任何变量,并且基于此,它实际上可以删除与此相关的任何处理。因为您注释掉了打印“value”的代码行,所以它感觉到这个变量不会在任何地方使用,也不会运行循环,甚至一次都不会

    但是当您打印值时,它必须运行循环,这也是一个非常大的数字(50000*100000000)。现在,这个循环的运行时间取决于很多因素,包括但不限于机器的处理器、提供给JVM的内存、处理器的负载等


    至于您关于eclipse无法终止它的问题,我可以在我的机器上使用eclipse轻松地终止该程序。也许您应该再次检查。

    这是一个JIT编译器优化(不是java编译器优化)

    如果比较java编译器为这两个版本生成的字节码,您将看到循环在这两个版本中都存在

    这是println的反编译方法的外观:

    private static void loop() {
        long value = 0L;
    
        for(int j = 0; j < '썐'; ++j) {
            for(int i = 0; i < 100000000; ++i) {
                ++value;
            }
        }
    
        System.out.println("Done " + value);
    }
    
    您可能还需要下载并放入您的工作目录(MacOS、HotSpot Java 8)

    运行TestClient之后,您应该可以在控制台中看到JIT编译器生成的代码。在这里,我将只发布输出的摘录

    不带println的版本:

    # {method} 'loop' '()V' in 'test/TestClient'
    0x000000010e3c2500: callq  0x000000010dc1c202  ;   {runtime_call}
    0x000000010e3c2505: data32 data32 nopw 0x0(%rax,%rax,1)
    0x000000010e3c2510: sub    $0x18,%rsp
    0x000000010e3c2517: mov    %rbp,0x10(%rsp)
    0x000000010e3c251c: mov    %rsi,%rdi
    0x000000010e3c251f: movabs $0x10dc760ec,%r10
    0x000000010e3c2529: callq  *%r10              ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x000000010e3c252c: add    $0x10,%rsp
    0x000000010e3c2530: pop    %rbp
    0x000000010e3c2531: test   %eax,-0x1c18537(%rip)        # 0x000000010c7aa000
                                                  ;   {poll_return}
    0x000000010e3c2537: retq
    
    带有println的版本:

    # {method} 'loop' '()V' in 'test/TestClient'
    0x00000001092c36c0: callq  0x0000000108c1c202  ;   {runtime_call}
    0x00000001092c36c5: data32 data32 nopw 0x0(%rax,%rax,1)
    0x00000001092c36d0: mov    %eax,-0x14000(%rsp)
    0x00000001092c36d7: push   %rbp
    0x00000001092c36d8: sub    $0x10,%rsp
    0x00000001092c36dc: mov    0x10(%rsi),%r13
    0x00000001092c36e0: mov    0x8(%rsi),%ebp
    0x00000001092c36e3: mov    (%rsi),%ebx
    0x00000001092c36e5: mov    %rsi,%rdi
    0x00000001092c36e8: movabs $0x108c760ec,%r10
    0x00000001092c36f2: callq  *%r10
    0x00000001092c36f5: jmp    0x00000001092c3740
    0x00000001092c36f7: add    $0x1,%r13          ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x00000001092c36fb: inc    %ebx               ;*iinc
                                                  ; - test.TestClient::loop@22 (line 9)
    0x00000001092c36fd: cmp    $0x5f5e101,%ebx
    0x00000001092c3703: jl     0x00000001092c36f7  ;*if_icmpge
                                                  ; - test.TestClient::loop@15 (line 9)
    0x00000001092c3705: jmp    0x00000001092c3734
    0x00000001092c3707: nopw   0x0(%rax,%rax,1)
    0x00000001092c3710: mov    %r13,%r8           ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x00000001092c3713: mov    %r8,%r13
    0x00000001092c3716: add    $0x10,%r13         ;*ladd
                                                  ; - test.TestClient::loop@20 (line 10)
    0x00000001092c371a: add    $0x10,%ebx         ;*iinc
                                                  ; - test.TestClient::loop@22 (line 9)
    0x00000001092c371d: cmp    $0x5f5e0f2,%ebx
    0x00000001092c3723: jl     0x00000001092c3710  ;*if_icmpge
                                                  ; - test.TestClient::loop@15 (line 9)
    0x00000001092c3725: add    $0xf,%r8           ;*ladd
                                                  ; - test.TestClient::loop@20 (line 10)
    0x00000001092c3729: cmp    $0x5f5e101,%ebx
    0x00000001092c372f: jl     0x00000001092c36fb
    0x00000001092c3731: mov    %r8,%r13           ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x00000001092c3734: inc    %ebp               ;*iinc
                                                  ; - test.TestClient::loop@28 (line 8)
    0x00000001092c3736: cmp    $0xc350,%ebp
    0x00000001092c373c: jge    0x00000001092c376c  ;*if_icmpge
                                                  ; - test.TestClient::loop@7 (line 8)
    0x00000001092c373e: xor    %ebx,%ebx
    0x00000001092c3740: mov    %ebx,%r11d
    0x00000001092c3743: inc    %r11d              ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x00000001092c3746: mov    %r13,%r8
    0x00000001092c3749: add    $0x1,%r8           ;*ladd
                                                  ; - test.TestClient::loop@20 (line 10)
    0x00000001092c374d: inc    %ebx               ;*iinc
                                                  ; - test.TestClient::loop@22 (line 9)
    0x00000001092c374f: cmp    %r11d,%ebx
    0x00000001092c3752: jge    0x00000001092c3759  ;*if_icmpge
                                                  ; - test.TestClient::loop@15 (line 9)
    0x00000001092c3754: mov    %r8,%r13
    0x00000001092c3757: jmp    0x00000001092c3746
    0x00000001092c3759: cmp    $0x5f5e0f2,%ebx
    0x00000001092c375f: jl     0x00000001092c3713
    0x00000001092c3761: mov    %r13,%r10
    0x00000001092c3764: mov    %r8,%r13
    0x00000001092c3767: mov    %r10,%r8
    0x00000001092c376a: jmp    0x00000001092c3729  ;*if_icmpge
                                                  ; - test.TestClient::loop@7 (line 8)
    0x00000001092c376c: mov    $0x24,%esi
    0x00000001092c3771: mov    %r13,%rbp
    0x00000001092c3774: data32 xchg %ax,%ax
    0x00000001092c3777: callq  0x0000000109298f20  ; OopMap{off=188}
                                                  ;*getstatic out
                                                  ; - test.TestClient::loop@34 (line 13)
                                                  ;   {runtime_call}
    0x00000001092c377c: callq  0x0000000108c1c202  ;*getstatic out
                                                  ; - test.TestClient::loop@34 (line 13)
                                                  ;   {runtime_call}
    
    此外,还应该有hotspot.log文件和JIT编译器步骤。以下是摘录:

    <phase name='optimizer' nodes='114' live='77' stamp='0.100'>
                <phase name='idealLoop' nodes='115' live='67' stamp='0.100'>
                    <loop_tree>
                        <loop idx='119' >
                            <loop idx='185' main_loop='185' >
                            </loop>
                        </loop>
                    </loop_tree>
                    <phase_done name='idealLoop' nodes='197' live='111' stamp='0.101'/>
                </phase>
                <phase name='idealLoop' nodes='197' live='111' stamp='0.101'>
                    <loop_tree>
                        <loop idx='202' >
                            <loop idx='159' inner_loop='1' pre_loop='131' >
                            </loop>
                            <loop idx='210' inner_loop='1' main_loop='210' >
                            </loop>
                            <loop idx='138' inner_loop='1' post_loop='131' >
                            </loop>
                        </loop>
                    </loop_tree>
                    <phase_done name='idealLoop' nodes='221' live='113' stamp='0.101'/>
                </phase>
                <phase name='idealLoop' nodes='221' live='113' stamp='0.101'>
                    <loop_tree>
                        <loop idx='202' >
                            <loop idx='159' inner_loop='1' pre_loop='131' >
                            </loop>
                            <loop idx='210' inner_loop='1' main_loop='210' >
                            </loop>
                            <loop idx='138' inner_loop='1' post_loop='131' >
                            </loop>
                        </loop>
                    </loop_tree>
                    <phase_done name='idealLoop' nodes='241' live='63' stamp='0.101'/>
                </phase>
                <phase name='ccp' nodes='241' live='63' stamp='0.101'>
                    <phase_done name='ccp' nodes='241' live='63' stamp='0.101'/>
                </phase>
                <phase name='idealLoop' nodes='241' live='63' stamp='0.101'>
                    <loop_tree>
                        <loop idx='202' inner_loop='1' >
                        </loop>
                    </loop_tree>
                    <phase_done name='idealLoop' nodes='253' live='56' stamp='0.101'/>
                </phase>
                <phase name='idealLoop' nodes='253' live='56' stamp='0.101'>
                    <phase_done name='idealLoop' nodes='253' live='33' stamp='0.101'/>
                </phase>
                <phase_done name='optimizer' nodes='253' live='33' stamp='0.101'/>
            </phase>
    
    
    
    您可以使用JitWatch工具进一步分析JIT编译器生成的hotspot.log文件

    要禁用JIT编译器并在所有解释模式下运行Java虚拟机,可以使用-Djava.compiler=NONE JVM选项


    这篇文章中也有一个类似的问题

    为什么打印结果值时要花时间执行?请注意,如果我不打印值,同样的循环会立即结束。

    说实话,我查了你的
    # {method} 'loop' '()V' in 'test/TestClient'
    0x00000001092c36c0: callq  0x0000000108c1c202  ;   {runtime_call}
    0x00000001092c36c5: data32 data32 nopw 0x0(%rax,%rax,1)
    0x00000001092c36d0: mov    %eax,-0x14000(%rsp)
    0x00000001092c36d7: push   %rbp
    0x00000001092c36d8: sub    $0x10,%rsp
    0x00000001092c36dc: mov    0x10(%rsi),%r13
    0x00000001092c36e0: mov    0x8(%rsi),%ebp
    0x00000001092c36e3: mov    (%rsi),%ebx
    0x00000001092c36e5: mov    %rsi,%rdi
    0x00000001092c36e8: movabs $0x108c760ec,%r10
    0x00000001092c36f2: callq  *%r10
    0x00000001092c36f5: jmp    0x00000001092c3740
    0x00000001092c36f7: add    $0x1,%r13          ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x00000001092c36fb: inc    %ebx               ;*iinc
                                                  ; - test.TestClient::loop@22 (line 9)
    0x00000001092c36fd: cmp    $0x5f5e101,%ebx
    0x00000001092c3703: jl     0x00000001092c36f7  ;*if_icmpge
                                                  ; - test.TestClient::loop@15 (line 9)
    0x00000001092c3705: jmp    0x00000001092c3734
    0x00000001092c3707: nopw   0x0(%rax,%rax,1)
    0x00000001092c3710: mov    %r13,%r8           ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x00000001092c3713: mov    %r8,%r13
    0x00000001092c3716: add    $0x10,%r13         ;*ladd
                                                  ; - test.TestClient::loop@20 (line 10)
    0x00000001092c371a: add    $0x10,%ebx         ;*iinc
                                                  ; - test.TestClient::loop@22 (line 9)
    0x00000001092c371d: cmp    $0x5f5e0f2,%ebx
    0x00000001092c3723: jl     0x00000001092c3710  ;*if_icmpge
                                                  ; - test.TestClient::loop@15 (line 9)
    0x00000001092c3725: add    $0xf,%r8           ;*ladd
                                                  ; - test.TestClient::loop@20 (line 10)
    0x00000001092c3729: cmp    $0x5f5e101,%ebx
    0x00000001092c372f: jl     0x00000001092c36fb
    0x00000001092c3731: mov    %r8,%r13           ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x00000001092c3734: inc    %ebp               ;*iinc
                                                  ; - test.TestClient::loop@28 (line 8)
    0x00000001092c3736: cmp    $0xc350,%ebp
    0x00000001092c373c: jge    0x00000001092c376c  ;*if_icmpge
                                                  ; - test.TestClient::loop@7 (line 8)
    0x00000001092c373e: xor    %ebx,%ebx
    0x00000001092c3740: mov    %ebx,%r11d
    0x00000001092c3743: inc    %r11d              ;*iload_3
                                                  ; - test.TestClient::loop@12 (line 9)
    0x00000001092c3746: mov    %r13,%r8
    0x00000001092c3749: add    $0x1,%r8           ;*ladd
                                                  ; - test.TestClient::loop@20 (line 10)
    0x00000001092c374d: inc    %ebx               ;*iinc
                                                  ; - test.TestClient::loop@22 (line 9)
    0x00000001092c374f: cmp    %r11d,%ebx
    0x00000001092c3752: jge    0x00000001092c3759  ;*if_icmpge
                                                  ; - test.TestClient::loop@15 (line 9)
    0x00000001092c3754: mov    %r8,%r13
    0x00000001092c3757: jmp    0x00000001092c3746
    0x00000001092c3759: cmp    $0x5f5e0f2,%ebx
    0x00000001092c375f: jl     0x00000001092c3713
    0x00000001092c3761: mov    %r13,%r10
    0x00000001092c3764: mov    %r8,%r13
    0x00000001092c3767: mov    %r10,%r8
    0x00000001092c376a: jmp    0x00000001092c3729  ;*if_icmpge
                                                  ; - test.TestClient::loop@7 (line 8)
    0x00000001092c376c: mov    $0x24,%esi
    0x00000001092c3771: mov    %r13,%rbp
    0x00000001092c3774: data32 xchg %ax,%ax
    0x00000001092c3777: callq  0x0000000109298f20  ; OopMap{off=188}
                                                  ;*getstatic out
                                                  ; - test.TestClient::loop@34 (line 13)
                                                  ;   {runtime_call}
    0x00000001092c377c: callq  0x0000000108c1c202  ;*getstatic out
                                                  ; - test.TestClient::loop@34 (line 13)
                                                  ;   {runtime_call}
    
    <phase name='optimizer' nodes='114' live='77' stamp='0.100'>
                <phase name='idealLoop' nodes='115' live='67' stamp='0.100'>
                    <loop_tree>
                        <loop idx='119' >
                            <loop idx='185' main_loop='185' >
                            </loop>
                        </loop>
                    </loop_tree>
                    <phase_done name='idealLoop' nodes='197' live='111' stamp='0.101'/>
                </phase>
                <phase name='idealLoop' nodes='197' live='111' stamp='0.101'>
                    <loop_tree>
                        <loop idx='202' >
                            <loop idx='159' inner_loop='1' pre_loop='131' >
                            </loop>
                            <loop idx='210' inner_loop='1' main_loop='210' >
                            </loop>
                            <loop idx='138' inner_loop='1' post_loop='131' >
                            </loop>
                        </loop>
                    </loop_tree>
                    <phase_done name='idealLoop' nodes='221' live='113' stamp='0.101'/>
                </phase>
                <phase name='idealLoop' nodes='221' live='113' stamp='0.101'>
                    <loop_tree>
                        <loop idx='202' >
                            <loop idx='159' inner_loop='1' pre_loop='131' >
                            </loop>
                            <loop idx='210' inner_loop='1' main_loop='210' >
                            </loop>
                            <loop idx='138' inner_loop='1' post_loop='131' >
                            </loop>
                        </loop>
                    </loop_tree>
                    <phase_done name='idealLoop' nodes='241' live='63' stamp='0.101'/>
                </phase>
                <phase name='ccp' nodes='241' live='63' stamp='0.101'>
                    <phase_done name='ccp' nodes='241' live='63' stamp='0.101'/>
                </phase>
                <phase name='idealLoop' nodes='241' live='63' stamp='0.101'>
                    <loop_tree>
                        <loop idx='202' inner_loop='1' >
                        </loop>
                    </loop_tree>
                    <phase_done name='idealLoop' nodes='253' live='56' stamp='0.101'/>
                </phase>
                <phase name='idealLoop' nodes='253' live='56' stamp='0.101'>
                    <phase_done name='idealLoop' nodes='253' live='33' stamp='0.101'/>
                </phase>
                <phase_done name='optimizer' nodes='253' live='33' stamp='0.101'/>
            </phase>