关于java:即使从不抛出异常,使用try-catch块是否昂贵?

Is it expensive to use try-catch blocks even if an exception is never thrown?

我们知道捕获异常是昂贵的。但是,即使在没有抛出异常的情况下,在Java中使用TestCcatch块也很昂贵吗?

我发现堆栈溢出问题/答案为什么try块昂贵?,但它是用于.NET的。


蛛网膜下腔出血(SAH)的费用try几乎在所有。而不是做的工作在运行时设置的try,元数据的结构化的代码在编译的时间是这样的,当异常是一个比较thrown现在很贵,不弹出堆栈行走操作和看到如果任何块的存在,会try捕获这个异常。从外行的角度来看,以及try可能是免费的。它的成本你真的是抛异常,但除非你抛异常:英皇直属领地奇尔特恩诸邑千欧,你仍然不会通知费用。

有一些轻微的try成本是相关联的。对于一些Java的代码块中的optimizations在线try另有它会的。例如,Java会经常重新安排指令的方法,使它在Java运行速度更快,但也需要担保,如果异常是thrown,方法的执行,它是观察到的语句,执行写在源代码中,一阶上的线。

因为try块中的异常可以在地图的任何thrown(try块中。一些异常是由thrown asynchronously stop在线呼叫,如线程(这是不提倡),此外,甚至可以发生outofmemoryerror几乎到处可以看到了),但它与代码继续运行在相同的方法讨论之后,更多的原因是,它是很难optimizations可以被制造的,所以他们是不可能会发生。(有人将要对他们的程序的编译器的正确性,因此在和担保等,会痛是什么大的意思是"特殊的"),但在实践中同样,你不会注意的东西像这样。


我们衡量它,我们?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public abstract class Benchmark {

    final String name;

    public Benchmark(String name) {
        this.name = name;
    }

    abstract int run(int iterations) throws Throwable;

    private BigDecimal time() {
        try {
            int nextI = 1;
            int i;
            long duration;
            do {
                i = nextI;
                long start = System.nanoTime();
                run(i);
                duration = System.nanoTime() - start;
                nextI = (i << 1) | 1;
            } while (duration < 100000000 && nextI > 0);
            return new BigDecimal((duration) * 1000 / i).movePointLeft(3);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String toString() {
        return name +"\t" + time() +" ns";
    }

    public static void main(String[] args) throws Exception {
        Benchmark[] benchmarks = {
            new Benchmark("try") {
                @Override int run(int iterations) throws Throwable {
                    int x = 0;
                    for (int i = 0; i < iterations; i++) {
                        try {
                            x += i;
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    return x;
                }
            }, new Benchmark("no try") {
                @Override int run(int iterations) throws Throwable {
                    int x = 0;
                    for (int i = 0; i < iterations; i++) {
                        x += i;
                    }
                    return x;
                }
            }
        };
        for (Benchmark bm : benchmarks) {
            System.out.println(bm);
        }
    }
}

在我的电脑打印的东西,这样:

1
2
try     0.598 ns
no try  0.601 ns

至少在这平凡的例子,在try语句没有影响性能的测度。免费测量更复杂的感觉。。。。。。。。

一般讲,我建议不要担心语言构建的性能成本,直到你有一个现有的证据在你的代码的性能问题。或把它:"Donald Knuth的过早的优化是一切邪恶的根源"。


可能有一些catchtry/性能的影响。这是因为它做一些optimizations从防止JVM(Java虚拟机)。Joshua Bloch在《Effective Java",说下面的:

? Placing code inside a try-catch block inhibits certain optimizations that modern JVM implementations might otherwise perform.


是的,有人说,在一些区块的抑制作用tryoptimizations {}人物周围它。特别是,该算法必须认为异常可以发生在任何点在块,所以没有保证这样的语句被执行。

例如:

1
2
3
4
5
6
7
8
9
    try {
        int x = a + b * c * d;
        other stuff;
    }
    catch (something) {
        ....
    }
    int y = a + b * c * d;
    use y somehow;

try没有计算到的值,assign x可以保存到"常见的子表达式和reused"到yassign)。但由于try是没有保证的,第一是人的表达系统表达的评估,必须重新计算。这是不是大的交易通常是在"直线"的代码,但可以在环的差异。

然而,它应该指出的是,这仅适用于jitced代码。不只是piddling javac优化的数量和成本,有一个零字节码解释器的try进入/离开块。(有)在生成的字节码,该区块的边界标记。

和bestsss:

1
2
3
4
5
6
7
8
9
10
public class TryFinally {
    public static void main(String[] argv) throws Throwable {
        try {
            throw new Throwable();
        }
        finally {
            System.out.println("Finally!");
        }
    }
}

输出:

1
2
3
4
C:\JavaTools>java TryFinally
Finally!
Exception in thread"main" java.lang.Throwable
        at TryFinally.main(TryFinally.java:4)

javap的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
C:\JavaTools>javap -c TryFinally.class
Compiled from"TryFinally.java"
public class TryFinally {
  public TryFinally();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Throwable;
    Code:
       0: new           #2                  // class java/lang/Throwable
       3: dup
       4: invokespecial #3                  // Method java/lang/Throwable."<init>":()V
       7: athrow
       8: astore_1
       9: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      12: ldc           #5                  // String Finally!
      14: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      17: aload_1
      18: athrow
    Exception table:
       from    to  target type
           0     9     8   any
}

在"goto"。


又一个微生物标记(来源)。

我创建了一个测试,在该测试中,我根据异常百分比度量try catch和no try catch代码版本。10%的百分比意味着10%的测试用例被零个用例划分。在一种情况下,它由try-catch块处理,而在另一种情况下则由条件运算符处理。这是我的结果表:

1
2
OS: Windows 8 6.2 x64
JVM: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 23.25-b01
1
2
3
4
5
Percentage | Result (try/if, ns)  
    0%     |      88/90  
    1%     |      89/87    
    10%    |      86/97    
    90%    |      85/83

也就是说,这些病例之间没有显著差异。


了解为什么optimizations不能执行的,它是有用的了解底层机制。我能找到的最succinct例子实现的是在C中的宏:http://hm2,www.di.unipi.it NIDS /文档/ _ _特罗_ catch.html LJ模式的尝试

1
2
3
4
5
6
7
#include <stdio.h>
#include <setjmp.h>
#define TRY do{ jmp_buf ex_buf__; switch( setjmp(ex_buf__) ){ case 0: while(1){
#define CATCH(x) break; case x:
#define FINALLY break; } default:
#define ETRY } }while(0)
#define THROW(x) longjmp(ex_buf__, x)

编译器有困难,往往是确定的,如果可以定跳到OS X,Y和Z是optimizations跳过他们,他们不能保证是安全的,但实现本身是相当轻的。


我发现捕捉nullpointexception非常昂贵。对于1.2公里的作业来说,我和if(object==null)的处理方法一样,时间是200毫秒和12毫秒,这对我来说是相当好的改进。