<Inside JVM>是市面上少数几本系统介绍JVM的书籍,(作者Bill Venners的网站
artima也是非常有趣的Java技术社区),这本书最有意思的地方可能就是作者为了演示JVM内部工作原理编写的
Applet, 非常值得向大家推荐。<Inside JVM>最新的是第二版,也有些年头了,尽管JVM规范本身的变化并不大,但是java编译器的有些细节处理还是跟书里面不一样了,比如说现在的java编译器一般都会对finally作inline处理。
这个 Applet演示的是下面这段程序的bytecode。
代码1:
其主要目的演示的是finally子句的处理, 在Inside JVM和JVM Spec的7.13节当中,finally都是通过jsr和ret指令实现的,按照书中的说法,hopAround()方法将被编译成47个jvm指令,如下所示:
代码2:
/**/
/*
*copiedfromhttp://www.artima.com/insidejvm/applets/HopAround.html
*/
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
0
iconst_0
//
Pushconstant0
1
istore_0
//
Popintolocalvar0:inti=0;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Bothtryblocksstarthere(seeexceptiontable,below):
2
iconst_1
//
Pushconstant1
3
istore_0
//
Popintolocalvar0:i=1;
4
jsr
18
//
Jumptomini-subroutineatoffset18(the
//
firstfinallyclause)
7
goto
24
//
Jumptooffset24(tojustbelowfirst
//
finallyclause)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Catchclauseforthefirstfinallyclause:
10
astore
4
//
Popthereferencetothrownexception,store
//
inlocalvariable4
12
jsr
18
//
Jumptomini-subroutineatoffset18(the
//
firstfinallyclause)
15
aload
4
//
Pushthereference(tothrownexception)
//
fromlocalvariable4
17
athrow
//
Rethrowthesameexception
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Thefirstfinallyclause:
18
astore
5
//
Storethereturnaddressinlocalvariable5
20
iconst_2
//
Pushconstant2
21
istore_0
//
Popintolocalvar0:i=2;
22
ret
5
//
Jumptoreturnaddressstoredinlocalvariable5
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Bytecodesforthecodejustafterthefirstfinallyclause:
24
iconst_3
//
Pushconstant3
25
istore_0
//
Popintolocalvar0:inti=3;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Bytecodesforthereturnstatment:
26
iload_0
//
Pushtheintfromlocal
//
variable0(i,whichis3)
27
istore_1
//
Popandstoretheintintolocal
//
variable1(thereturnvalue,i)
28
jsr
39
//
Jumptomini-subroutineatoffset39(the
//
secondfinallyclause)
31
iload_1
//
Pushtheintfromlocalvariable1(the
//
returnvalue)
32
ireturn
//
Returntheintonthetopofthestack
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Catchclauseforthesecondfinallyclause:
33
astore_2
//
Popthereferencetothrownexception,store
//
inlocalvariable2
34
jsr
39
//
Jumptomini-subroutineatoffset39(the
//
secondfinallyclause)
37
aload_2
//
Pushthereference(tothrownexception)
//
fromlocalvariable2
38
athrow
//
Rethrowthesameexception
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Thesecondfinallyclause:
39
astore_3
//
Storethereturnaddressinlocalvariable3
40
iload_0
//
Pushtheintfromlocalvariable0(i)
41
iconst_3
//
Pushconstant3
42
if_icmpeq
47
//
Ifthetoptwointsonthestackareequal,jump
//
tooffset47:if(i==3){
45
ret
3
//
Jumptoreturnaddressstoredinlocalvariable3
47
goto
2
//
Jumptooffset2(thetopofthewhile
//
block):continue;
但是如果用Sun JDK 1.4之后的编译器编译,这段程序实际上被编译成截然不同的38个jvm指令(如下所示),其主要区别是finally 子句被inline到了正常代码和exception handling代码,避免了jsr/ret, 从而减少了JSR跳转/pop出栈/ret返回三条指令,在本例中,不但提高了运行效率,还减少了class文件的大小,其代价是finally block之中的内容被复制到了两个地方,如果finally block的指令很多,class文件可能会变大。
代码3:
Eclipse编译器显然也将finally inline了,Eclipse 3.2甚至disable了编译器不inline finally的选项,ECJ编译出来的hopAround()由39条指令组成:
代码4:
static
int
hopAround();
Code:
0
:iconst_0
1
:istore_0
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
startbothtry
2
:iconst_1
3
:istore_0
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
skipexceptionhandling
4
:
goto
12
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
exceptionhandlingforfirsttryblock
7
:astore_1
//
firstfinallyblockinlined
8
:iconst_2
9
:istore_0
10
:aload_1
11
:athrow
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
firstfinallyblockinlinedagain
12
:iconst_2
13
:istore_0
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
goonsecondtryblock
14
:iconst_3
15
:istore_0
16
:iload_0
17
:istore_3
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
secondfinallyblockinlined
18
:iload_0
19
:iconst_3
20
:if_icmpne
26
23
:
goto
2
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
return
26
:iload_3
27
:ireturn
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
exceptionhandlingforsecondtry
28
:astore_2
//
secondefinallyinlined
29
:iload_0
30
:iconst_3
31
:if_icmpne
37
34
:
goto
2
37
:aload_2
38
:athrow
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
whatdoesthismean?
39
:
goto
2
Exceptiontable:
fromtotargettype
2
7
7
any
2
18
28
any
区别不大,Eclipse编译器将exception handling的代码放在了正常路径的finally block之前,多出来的一句是第39句goto 2, 比较匪夷所思, 因为这一句显然是无法被执行到的。还有一个区别是exception table缩减为两项,少掉的两条是针对exception handling代码自身的,Sun javac加上的这两条意欲何为也有点让人迷惑...也许因为这个原因,ECJ编译出来的class要稍微小一些(对于这个class, 222bytes vs. 235bytes)。
这两种主流Java编译器都对finally做了inline处理,所以我们在平常写java代码的时候应该注意在try/catch/finally里面不要做太多的分支,并且finally block中包含的内容尽量不要太多,否则class文件可能会多占用不少空间。
还有一个tips: javac和Eclipse编译器缺省都带有debug信息,加上-g:none选项之后,class文件要小一半,对于Eclipse编译器尤其明显。
最后一个tips送给有耐心读到这里的人: 请代码3中的14-17行,在进入finally block之前,JVM将把变量i当前的值存入另外一个本地变量(istore_1),并且在26-27行将此值返回,所以如果在finally block中修改了i的值,对返回值是没有影响的,如果要将修改过的i返回,请在finally中直接return i。更多finally实现的细节请参考Inside JVM:).
这个 Applet演示的是下面这段程序的bytecode。
代码1:
/*
*copiedfrom http://www.artima.com/insidejvm/applets/HopAround.html
*/
class Clown...{
static int hopAround()...{
int i = 0 ;
while ( true )...{
try ...{
try ...{
i = 1 ;
}
finally ...{ // Thefirstfinallyclause
i = 2 ;
}
i = 3 ;
// Thisreturnnevercompletes,becauseof
// thecontinueinthesecondfinallyclause
return i;
}
finally ...{ // Thesecondfinallyclause
if (i == 3 )...{
// Thiscontinueoverridesthereturnstatement
continue ;
}
}
}
}
}
*copiedfrom http://www.artima.com/insidejvm/applets/HopAround.html
*/
class Clown...{
static int hopAround()...{
int i = 0 ;
while ( true )...{
try ...{
try ...{
i = 1 ;
}
finally ...{ // Thefirstfinallyclause
i = 2 ;
}
i = 3 ;
// Thisreturnnevercompletes,becauseof
// thecontinueinthesecondfinallyclause
return i;
}
finally ...{ // Thesecondfinallyclause
if (i == 3 )...{
// Thiscontinueoverridesthereturnstatement
continue ;
}
}
}
}
}
其主要目的演示的是finally子句的处理, 在Inside JVM和JVM Spec的7.13节当中,finally都是通过jsr和ret指令实现的,按照书中的说法,hopAround()方法将被编译成47个jvm指令,如下所示:
代码2:
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
但是如果用Sun JDK 1.4之后的编译器编译,这段程序实际上被编译成截然不同的38个jvm指令(如下所示),其主要区别是finally 子句被inline到了正常代码和exception handling代码,避免了jsr/ret, 从而减少了JSR跳转/pop出栈/ret返回三条指令,在本例中,不但提高了运行效率,还减少了class文件的大小,其代价是finally block之中的内容被复制到了两个地方,如果finally block的指令很多,class文件可能会变大。
代码3:
static
int
hopAround();
Code:
0 :iconst_0 // pushconst0
1 :istore_0 // popintolocalvar0:i=0
// startbothtryblock
2 :iconst_1 // pushconst1
3 :istore_0 // popintoi
// startfirstfinallyblock(itisinlined)
4 :iconst_2 // pushconst2
5 :istore_0 // popintolocalvar0(i)
6 : goto 14 // skipexceptionhandling
// startexceptionhandlingforsecondtryblock
9 :astore_1 // popthrownexceptionreferenceintolocalvar1
// startfirstfinallyblock(inlineagain)
10 :iconst_2 // pushconst2
11 :istore_0 // popinto0
12 :aload_1 // pushthereference(theexception)fromlocalvar1
13 :athrow // throwexeption
// goonthefirsttryblock
14 :iconst_3 // pushconst3
15 :istore_0 // popintolocalvar0(i)
16 :iload_0 // pushvaluefromlocalvar0(i)
17 :istore_1 // popintolocalvar1(returnvalue)
// startsecondfinallyblock(inlined)
18 :iload_0 // pushvaluefromlocalvar0(i)
19 :iconst_3 // pushconst3
20 :if_icmpne 26 // ifthetoptwointsonthestackarenotequal,jumpto26
23 : goto 2 // loop
// goonthefirsttryblock
26 :iload_1 // pushvaluefromlocalvar1(returnvalue)
27 :ireturn // returnmethod
// startexceptionhandlingforfirsttryblock
28 :astore_2 // popthrownexceptionreferenceintolocalvar2
// startsecondfinallyblock(inlinedagain)
29 :iload_0 // pushvaluefromlocalvar0(i)
30 :iconst_3 // pushconst3
31 :if_icmpne 37 // ifthetoptwointsonthestackarenotequal,jumpto37
34 : goto 2 // loop
37 :aload_2 // pushthereference(theexception)fromlocalvar2
38 :athrow // throwexception
Exceptiontable:
fromtotargettype
2 4 9 any
9 10 9 any
2 18 28 any
28 29 28 any
Code:
0 :iconst_0 // pushconst0
1 :istore_0 // popintolocalvar0:i=0
// startbothtryblock
2 :iconst_1 // pushconst1
3 :istore_0 // popintoi
// startfirstfinallyblock(itisinlined)
4 :iconst_2 // pushconst2
5 :istore_0 // popintolocalvar0(i)
6 : goto 14 // skipexceptionhandling
// startexceptionhandlingforsecondtryblock
9 :astore_1 // popthrownexceptionreferenceintolocalvar1
// startfirstfinallyblock(inlineagain)
10 :iconst_2 // pushconst2
11 :istore_0 // popinto0
12 :aload_1 // pushthereference(theexception)fromlocalvar1
13 :athrow // throwexeption
// goonthefirsttryblock
14 :iconst_3 // pushconst3
15 :istore_0 // popintolocalvar0(i)
16 :iload_0 // pushvaluefromlocalvar0(i)
17 :istore_1 // popintolocalvar1(returnvalue)
// startsecondfinallyblock(inlined)
18 :iload_0 // pushvaluefromlocalvar0(i)
19 :iconst_3 // pushconst3
20 :if_icmpne 26 // ifthetoptwointsonthestackarenotequal,jumpto26
23 : goto 2 // loop
// goonthefirsttryblock
26 :iload_1 // pushvaluefromlocalvar1(returnvalue)
27 :ireturn // returnmethod
// startexceptionhandlingforfirsttryblock
28 :astore_2 // popthrownexceptionreferenceintolocalvar2
// startsecondfinallyblock(inlinedagain)
29 :iload_0 // pushvaluefromlocalvar0(i)
30 :iconst_3 // pushconst3
31 :if_icmpne 37 // ifthetoptwointsonthestackarenotequal,jumpto37
34 : goto 2 // loop
37 :aload_2 // pushthereference(theexception)fromlocalvar2
38 :athrow // throwexception
Exceptiontable:
fromtotargettype
2 4 9 any
9 10 9 any
2 18 28 any
28 29 28 any
Eclipse编译器显然也将finally inline了,Eclipse 3.2甚至disable了编译器不inline finally的选项,ECJ编译出来的hopAround()由39条指令组成:
代码4:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
区别不大,Eclipse编译器将exception handling的代码放在了正常路径的finally block之前,多出来的一句是第39句goto 2, 比较匪夷所思, 因为这一句显然是无法被执行到的。还有一个区别是exception table缩减为两项,少掉的两条是针对exception handling代码自身的,Sun javac加上的这两条意欲何为也有点让人迷惑...也许因为这个原因,ECJ编译出来的class要稍微小一些(对于这个class, 222bytes vs. 235bytes)。
这两种主流Java编译器都对finally做了inline处理,所以我们在平常写java代码的时候应该注意在try/catch/finally里面不要做太多的分支,并且finally block中包含的内容尽量不要太多,否则class文件可能会多占用不少空间。
还有一个tips: javac和Eclipse编译器缺省都带有debug信息,加上-g:none选项之后,class文件要小一半,对于Eclipse编译器尤其明显。
最后一个tips送给有耐心读到这里的人: 请代码3中的14-17行,在进入finally block之前,JVM将把变量i当前的值存入另外一个本地变量(istore_1),并且在26-27行将此值返回,所以如果在finally block中修改了i的值,对返回值是没有影响的,如果要将修改过的i返回,请在finally中直接return i。更多finally实现的细节请参考Inside JVM:).