我们知道捕获异常是昂贵的。但是,即使在没有抛出异常的情况下,在Java中使用TestCcatch块也很昂贵吗?
我发现堆栈溢出问题/答案为什么try块昂贵?,但它是用于.NET的。
- 据我所知,在Java中尝试块非常便宜。
- 这个问题真的没有意义。尝试..捕获有一个非常具体的目的。如果你需要它,你就需要它。在任何情况下,一次尝试没有收获有什么意义?
- 如果不在块中使用finally,是否可以不使用catch进行尝试?
- try { /* do stuff */ } finally { /* make sure to release resources */ }是合法和有用的
- 这一成本必须与收益相权衡。它并不孤单。在任何情况下,昂贵是相对的,在你知道你做不到之前,使用最明显的方法是有意义的,而不是不做一些事情,因为它可能在一个小时的程序执行过程中节省你一两毫秒。
- 链接的问题讨论的不是"昂贵"的try,而是处理异常并展开堆栈。如果需要处理异常,则需要处理异常。
- @A4L从来不知道这是可能的,有趣的。
- @用户2246674有时您在一个方法开关中打开资源,即使该方法在某个点抛出异常,您也绝对希望关闭它。最后一个块保证执行。
- 我希望这不会导致"让我们重新发明错误代码"类型的情况…
- @safx:使用java7,您甚至可以使用try-with-resources摆脱finally块。
- 这个答案是:stackoverflow.com/a/10978562/330315声称try块本身没有任何成本。
- @Johnfx我把这个问题解释为关于Try-Catch的问题:"…使用一个Try-Catch块…,但对于Catch块,很少执行。这个问题可能会影响声明一个方法来抛出检查过的异常的成本。
- @约翰克斯有一个问题。如果try很昂贵,那么您可以在返回结果的类上提供一个替代方法,而不是抛出异常。例如,从c:int.Parse()对int.TryParse(...)。
- @johnfx不是没有catch的尝试,而是带有很少触发的异常的尝试catch。
- 我不明白这个问题在短短几天内有48个赞成票和答案,以及2公里以上的观点?某种广告??正如最受欢迎的评论所说,这是毫无意义的!如果需要处理异常情况,则必须有捕获物;您要将"昂贵"与什么进行比较?撞车了?
- @quinestor认为注释错误,请继续阅读,我在问,如果我们有一个try-catch块,但是异常从未发生(或很少发生),它是否会影响try中代码的性能…
- 杰西,这个问题是关于Java的,这一个StAdppOrth.com /问题/ 1308432 / /Helip;
- @johnfx'never occurs'=未引发,则try catch块不应存在。很少"伤害表现"?什么是性能比较?与不处理异常和发生崩溃相比?
- @阿纳卡塔,你是对的。我完全错过了。我的错误。
- @ JordFX EDCOX1〔7〕(或,用ARM在爪哇,简单地EDCOX1〔1〕)块中有大量的好代码。你肯定不需要catch是有用的,大多数问题(除了例外)都源于不正确的catch块。
蛛网膜下腔出血(SAH)的费用try几乎在所有。而不是做的工作在运行时设置的try,元数据的结构化的代码在编译的时间是这样的,当异常是一个比较thrown现在很贵,不弹出堆栈行走操作和看到如果任何块的存在,会try捕获这个异常。从外行的角度来看,以及try可能是免费的。它的成本你真的是抛异常,但除非你抛异常:英皇直属领地奇尔特恩诸邑千欧,你仍然不会通知费用。
有一些轻微的try成本是相关联的。对于一些Java的代码块中的optimizations在线try另有它会的。例如,Java会经常重新安排指令的方法,使它在Java运行速度更快,但也需要担保,如果异常是thrown,方法的执行,它是观察到的语句,执行写在源代码中,一阶上的线。
因为try块中的异常可以在地图的任何thrown(try块中。一些异常是由thrown asynchronously stop在线呼叫,如线程(这是不提倡),此外,甚至可以发生outofmemoryerror几乎到处可以看到了),但它与代码继续运行在相同的方法讨论之后,更多的原因是,它是很难optimizations可以被制造的,所以他们是不可能会发生。(有人将要对他们的程序的编译器的正确性,因此在和担保等,会痛是什么大的意思是"特殊的"),但在实践中同样,你不会注意的东西像这样。
- 有些异常是异步抛出的,它们不是异步的,而是在安全点中抛出的。这部分尝试有一些小成本与之相关。Java无法对一个尝试块中的代码进行优化,否则它将需要一个严重的引用。在某种程度上,代码很可能在try/catch块中。Try/Catch块可能更难内联并为结果构建适当的格,但w/重新排列的部分不明确。
- 没有catch的try...finally块是否也阻止了一些优化?
- @Patashu"实际上是抛出了一个让你付出代价的异常",从技术上讲,抛出异常并不昂贵;实例化Exception对象需要花费大部分时间。
我们衡量它,我们?
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的过早的优化是一切邪恶的根源"。
- 虽然在大多数JVM中,尝试/不尝试很可能是相同的,但是微基准存在严重的缺陷。
- 怎么会有缺陷?
- 相当多的级别:您的意思是结果是在1ns以下计算的?编译后的代码将同时删除try/catch和循环(从1到n的求和是一个简单的算术级数和)。即使代码包含try/finally编译器也可以证明,其中没有什么可以抛出的。抽象代码只有两个调用站点,将被克隆和内联。还有更多的情况,只要查阅一些关于微基准的文章,就可以决定编写一个微基准,始终检查生成的程序集。
- 报告的时间是循环的每次迭代。因为只有当总运行时间大于0.1秒(或20亿次迭代,这里不是这样的情况)时才会使用度量,我发现您的断言很难相信循环已被完全删除-因为如果循环已被删除,执行0.1秒需要什么?
- …实际上,根据-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly,循环和其中的加法都存在于生成的本机代码中。不,抽象方法不是内联的,因为它们的调用方不仅是及时编译的(可能是因为调用次数不够)。
- 如何在Java中编写正确的微基准:StAdppOrth.COM/问题/ 504103/& Helip;
- @瓦兹姆:我知道那个链接…你想让我注意其中哪一个最佳实践?据我所知,上面的标杆工具完全满足了所有这些要求…除了使用库之外,因为在堆栈溢出答案中链接库会使验证我的测量值更加困难。
可能有一些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.
- "它阻止了JVM进行一些优化"…?你能详细解释一下吗?
- @Try块内的kraken代码(通常是?总是?)例如,不能使用try块之外的代码重新排序。
- 请注意,问题是"它是否昂贵",而不是"它是否对性能有任何影响"。
- 添加了一个有效Java的摘录,当然,这是Java的圣经;除非有引用,否则摘录没有任何说明。实际上,Java中的任何代码都在某种程度上尝试着。
是的,有人说,在一些区块的抑制作用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"。
- 没有生成用于标记块边界的字节码,这不一定——它需要goto离开块,否则它将落入catch/finally帧。
- @bestsss——即使生成了goto(不是给定的),但成本很小,而且它远不是块边界的"标记",也可以为许多构造生成goto。
- 我从来没有提到成本,但是没有生成字节码是一个错误的语句。这就是全部。实际上,字节码中没有块,帧不等于块。
- 如果尝试直接落在finally中,就不会有goto,并且还有其他没有goto的场景。重点是"enter try"/"exit try"字节码的顺序上没有任何内容。
- 如果尝试直接落入finally-false,就不会有goto了!字节码中没有finally,它是try/catch(Throwable any){...; throw any;},它确实有catch语句,带有一个必须定义(非空)的frame和throwable,等等。为什么你要争论这个话题,你至少可以检查一些字节码?IMPL的当前准则。of finally是复制块并避免goto部分(前面的impl),但是必须复制字节码,这取决于有多少个出口点。
- 我没有说字节码中有最后一个。不过在Java中有一个。
又一个微生物标记(来源)。
我创建了一个测试,在该测试中,我根据异常百分比度量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跳过他们,他们不能保证是安全的,但实现本身是相当轻的。
- 您为Time/catch所找到的这些C宏不等价于Java或c++实现,它发出0个运行时指令。
- Java实现太过广泛,不能完全包含,这是一个简化的实现,目的是了解如何实现异常的基本思想。说它发出0运行时指令是误导性的。例如,一个简单的CLSASTASExtExchange扩展了RunTimeExchange,该异常扩展了可扩展的异常,该异常涉及到:GRIPCODCONT.COM/FILE/RealStury.GrpCult.COM/Java/Roo/JDK/OPEN/ZWNJ;和8203;JDK/& Helip;这就像是说,如果只使用了1个案例,那么C中的开关案例是免费的,仍然有一个很小的启动开销。
- try的开销在编译时消耗,类似于编译器在编译时将计算int a = 1 + 1;的成本作为常量2,而不是在运行时完成。这是不可否认的复杂性,但是如果没有抛出异常,就不会在运行时做任何额外的工作。
- @无论是否使用过这些预编译位,启动时都必须加载它们。没有办法知道在编译时的运行时是否会出现内存不足的异常——这就是为什么它们被称为运行时异常——否则它们将是编译器警告/错误,所以不,它不会优化所有东西,处理它们的所有代码都包含在编译后的代码中,并且有启动成本。
- 在某些平台(并非所有平台)上,编译器可以在比较/跳转到单个指令的同时优化预期的操作,因此您可能永远不会看到x86上的开销,请参阅:unixwiz.net/techttips/x86-jumps.html,但在没有那么多组合比较/跳转指令的mips/arm上可能会看到。这不是一个巨大的开销,但相当于用开关盒检查C中的返回值,非错误结果为"默认:"case。但如果你能证明,否则我会非常有兴趣看到这样的巫毒代码,可以做的东西,而没有代码为它。
- 我不能用C语言和Java来谈论C.,尝试是通过添加元数据而不是代码来实现的。当输入try块时,不会执行任何操作来指示这一点——当抛出异常时,将释放堆栈并检查该异常类型处理程序的元数据(代价高昂)。
- 让我们在聊天中继续讨论
- 是的,我实际上已经实现了一个Java解释器和静态字节码编译器,并在随后的JITC(IBM iSISE)上工作,并且我可以告诉你没有什么"标记"字节码中的尝试范围的入口/出口,而是在单独的表中标识这些范围。解释器对一个try范围不做任何特殊的操作(直到引发异常)。如前所述,JITC(或静态字节码编译器)必须知道限制优化的边界。
我发现捕捉nullpointexception非常昂贵。对于1.2公里的作业来说,我和if(object==null)的处理方法一样,时间是200毫秒和12毫秒,这对我来说是相当好的改进。