字节码的另一个内存安全防护是数组操作。'aastore' 和 'aaload' 字节码操作Java数组并且它们总是检查数组边界。如果调用程序越过了数组尾,这些字节码将抛出一个ArrayIndexOutOfBoundsException。也许所有最重要的检查都使用分支指令,例如,以if开始的字节码。在字节码中,分支指令只能转移到同一方法中的其它指令。在方法外可以传递的唯一控制是使它返回:抛出一个异常或者执行一个'invoke'指令。这不仅关闭了很多攻击,同时也防止由于摇荡引用(dangling reference)或者堆栈冲突而引发的令人厌恶的错误。如果你曾经使用系统调试器打开你的程序并定位到代码中的一个随机的位置,那么你会很熟悉这些错误。 我爱电脑技术社区--打造最好的电脑技术自学交流平台* @, p$ ^7 q( N' B7 u! h$ y# \5 N
1 Z, x* B& J- j! L
( w4 S. `8 H/ r! O& \# i: ]$ _所有这些检查中需要记住的重要的一点是它们是由虚拟机在字节码级进行的而不是仅仅由编译器在源代码级进行的。一个例如c++这样的语言的编译器可能在编译时预防上面讨论的某些内存错误,但是这些保护只是在源代码级应用。操作系统将很乐意加载执行任何机器码,无论这些代码是由精细的c++编译器产生的还是心怀恶意的攻击者产生的。简单的讲,C++仅仅是在源代码级上面向对象而Java的面向对象的特性扩展到编译过的代码级。
( @' _+ u5 c- D# \ ~www.520diannao.com
" p; u# Z- i" D8 O3 T我爱电脑技术社区--打造最好的电脑技术自学交流平台我爱电脑技术社区--打造最好的电脑技术自学交流平台# B& w' ?; d8 j$ f: I/ B& \8 d
分析字节码提升代码质量
+ I( h- h; V$ X6 `6 O$ B& \* C电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
( \7 f7 p$ {( ^+ H8 I我爱电脑技术社区--打造最好的电脑技术自学交流平台
* M1 e8 `4 O9 ^ u) d我爱电脑技术论坛Java字节码的内存和安全保护无论我们是否注意都是存在地,那么我们为什么还费心查看字节码呢?在很多情况下,知道编译器如何将你的代码转换为字节码可以帮助你写出更高效的代码,而且在某些情况下可以防止不易发觉的错误。考虑下面的例子:
7 z3 p9 O! @; c9 n8 ]5 v {打造最好的电脑自学交流论坛
& d; ]& M7 d, `( G( y8 p我爱电脑技术社区--打造最好的电脑技术自学交流平台
! s6 N" s$ f) [) p! _; {7 V. Y# }我爱电脑技术论坛//返回 str1+str2 的串连 我爱电脑技术社区--打造最好的电脑技术自学交流平台6 S$ e9 t" u3 J) l( e2 e1 L
我爱电脑技术社区--打造最好的电脑技术自学交流平台; @3 f9 |" U9 ~2 z/ A' S
String concat(String str1, String str2) { 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站5 g$ L7 t: H; ~) f* U* f
" k+ B* w% Z1 z7 `( l7 Y& O6 a
return str1 + str2; 打造最好的电脑自学交流论坛% K) n4 z. w' {2 x$ S( f& P
+ c& @; B6 K. {4 [# A8 j2 swww.520diannao.com} 6 W9 S+ p) |+ I& P2 D% y' m5 X6 e$ o
% V7 O8 T0 L8 }; }
- N- l9 d9 Z3 }, t4 K8 d, j" Jwww.520diannao.com//将 str2 附加到 str1
; q3 J. b7 C/ [0 a0 lwww.520diannao.com打造最好的电脑自学交流论坛% L7 H: e- l4 w: w! i d( [
void concat(StringBuffer str1, String str2) { 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站$ \ E0 I$ w: x$ \9 h
打造最好的电脑自学交流论坛: a3 n7 l: O, e. w
str1.append(str2);
6 n7 R* V" k; y" [+ A0 _( t# Swww.520diannao.com
4 X9 D# z1 B" q6 |} 打造最好的电脑自学交流论坛% y9 c) P1 \8 ^0 W. N* q9 K! R
+ a: X# K, \8 r3 E
我爱电脑技术社区--打造最好的电脑技术自学交流平台6 {/ V6 S! ^2 J/ y6 F x
猜猜每个方法需要多少个方法调用。现在编译这些方法并且运行javap,你会得到类似下面的输出: 我爱电脑技术社区--打造最好的电脑技术自学交流平台7 P% F; o. V) P: }, E
我爱电脑技术社区--打造最好的电脑技术自学交流平台6 B4 K7 g& y5 E. h) [5 a( Z2 v
+ e! d' h+ _* o* C; x' a打造最好的电脑自学交流论坛Method java.lang.String concat1(java.lang.String, java.lang.String)
/ N1 `' z4 D- N% w; L7 b电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
7 D2 I* k9 R/ M3 F: p* `www.520diannao.com0 new #5 www.520diannao.com2 P6 K% C" p v, N+ J$ D7 U
0 U" ?" ?5 w! n/ G: E" J
3 dup
_: N" f: [7 _打造最好的电脑自学交流论坛
/ m$ x* B0 U: [/ }1 V" h- R7 U& h# q我爱电脑技术论坛4 invokespecial #6
. `8 z, I' l1 T6 E我爱电脑技术论坛
c8 J6 y. g7 t/ {- q电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站7 aload_1
, m- E* n6 h4 R% W* w4 q我爱电脑技术社区--打造最好的电脑技术自学交流平台
+ d% f$ R2 @# ^- P) E n我爱电脑技术论坛8 invokevirtual #7 www.520diannao.com" N6 ?- k w. J, p" _8 \9 F
打造最好的电脑自学交流论坛" u# |# A( d9 [# B" K% S1 B8 I
11 aload_2
; i6 K. D/ v% L我爱电脑技术论坛, f5 N6 j! E4 j, v3 g% [# `+ L
12 invokevirtual #7
( E2 H! d; E- w5 l8 K电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
* ]9 U9 w7 G% q3 ~3 a8 N% D我爱电脑技术论坛15 invokevirtual #8
8 ?5 G9 l4 k _6 n: d0 c) z5 \+ w. _打造最好的电脑自学交流论坛
, \# S& g. k: w: j0 K5 H' y; U/ F电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站18 areturn 我爱电脑技术论坛: M: ~& Y; I& v0 D% }+ g
0 k+ ]1 V `) r7 ^' U, j% y# M, |0 _我爱电脑技术社区--打造最好的电脑技术自学交流平台Method void concat2(java.lang.StringBuffer, java.lang.String)
8 F+ S/ m/ w9 z$ E6 z9 l0 ]
% m7 }( v8 b- b% c" X我爱电脑技术论坛0 aload_1
j! t5 m2 T+ G C. ?0 n我爱电脑技术论坛
; V- P( `' f; t* X( Iwww.520diannao.com1 aload_2
2 ^/ W( X# e8 y. g t5 ?我爱电脑技术论坛
) m/ C, a# n) [6 ~' A电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站2 invokevirtual #7
- k! o4 T; _! ?9 E我爱电脑技术论坛. a$ u3 k; D- o! N. F2 F. e
5 pop
! i5 d: G& Q& O$ {- p6 C/ Awww.520diannao.com
1 C& l7 x" f5 m8 p2 l V, X, e6 J电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站6 return
4 A% ?/ A E W! |1 X$ R打造最好的电脑自学交流论坛
- s! p5 r- `; b3 T1 q( \ Q我爱电脑技术社区--打造最好的电脑技术自学交流平台) q) B# a7 r/ z4 R9 g3 b
concat1方法执行了5个方法调用s: new, invokespecial和三个invokevirtuals,这比concat2方法执行了更多的工作,后者只执行了一个invokevirtual调用。大多Java程序员已经得到过警告,因为String是不可变的,而使用StringBuffer进行字符串连接效率更高。使用javap分析这个使得这点变得很生动。如果你不能肯定两个语言构造在性能上是否相等,你应该使用javap分析字节码。然而,对just-in-time (JIT)编译器要小心,因为JIT编译器将字节码重新编译为本机代码而能执行一些javap不能揭示的附加优化。除非你有你的虚拟机的源代码,否则你应该补充你的字节码的基准性能分析。 打造最好的电脑自学交流论坛2 B+ Y! _0 t3 l4 t ?
我爱电脑技术社区--打造最好的电脑技术自学交流平台 s6 r, o) k* ?2 Z
, f7 e/ i+ I9 Y5 P0 ^
最后的一个范例展示了检查字节码如何帮助防止程序中的错误。像下面那样创建两个类,确保它们在独立的文件中。 我爱电脑技术社区--打造最好的电脑技术自学交流平台( U6 |% p7 g) y+ ?- Z6 P- \
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站" Z5 K& C' |: E
( E+ @ M! k' e, L' l打造最好的电脑自学交流论坛public class ChangeALot {
. J) S1 c& I$ Q* a1 o0 lwww.520diannao.com我爱电脑技术社区--打造最好的电脑技术自学交流平台( P7 ^; v2 o6 _- w l& S, V3 w
public static final boolean debug=false; 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站6 h' K! Q! O y$ A( g% k
我爱电脑技术社区--打造最好的电脑技术自学交流平台4 q, j! F) f, n' A+ i1 I
public static boolean log=false;
8 S W% c" l. t+ {# t; g* |我爱电脑技术社区--打造最好的电脑技术自学交流平台电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站$ R0 W$ ~, \! s+ {6 c* h
} 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站4 C4 P$ u' r/ ~' W( @$ [
7 a; [7 x3 v7 D1 k9 E. c我爱电脑技术论坛5 W4 G1 O* R: T( z7 K$ Z* X( q
public class EternallyConstant { 打造最好的电脑自学交流论坛8 k' G1 C: j7 p8 g% [5 ?& e
- U2 y" Z; ?& }; I! ~) E& E( N电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站public static void main(String [] args) { 我爱电脑技术社区--打造最好的电脑技术自学交流平台0 x* g/ c+ O* A% v
打造最好的电脑自学交流论坛( F3 B$ S/ a5 ~/ s+ t/ a+ s4 l4 C
System.out.println("EternallyConstant beginning execution"); 我爱电脑技术论坛, W1 |* C# a5 c# g1 Z% I/ j
. ~# K# g+ D, ~9 g+ e `2 k8 t我爱电脑技术社区--打造最好的电脑技术自学交流平台if (ChangeALot.debug)
4 H) G7 W2 ^: w: X1 c5 |' a5 p+ W我爱电脑技术论坛
% g' z( f- O7 W" g& j% i/ g" u4 U6 g打造最好的电脑自学交流论坛System.out.println("Debug mode is on");
/ k$ m) i6 G( `0 ~( e5 t0 b我爱电脑技术论坛我爱电脑技术社区--打造最好的电脑技术自学交流平台; ?/ X2 L* `4 `0 b, o
if (ChangeALot.log) 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站+ G9 y) m: t9 M) Z0 _- O
$ x: m3 T4 m z6 q, N
System.out.println("Logging mode is on"); www.520diannao.com% C: @5 P9 ^+ t! w2 `
6 G# _% z& m$ g} 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站+ G% u$ q! x" S2 C8 Y. ^3 S; V
我爱电脑技术社区--打造最好的电脑技术自学交流平台% p5 b" h3 l, ]* B* Y: ^5 \
} 我爱电脑技术社区--打造最好的电脑技术自学交流平台" O# Q H1 K" z2 w1 ~# b! e. t
; ~, Q2 u- ], x( o+ W" b; J我爱电脑技术论坛电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站& h( w2 C' Q: G: p* O$ w" w! J, ?, D
如果你运行EternallyConstant,你会得到信息:
6 {2 y+ ^' Z* x# Rwww.520diannao.com# `3 b6 x7 c: m8 @0 l H* N% i9 V
8 _& [8 A( N) ~7 Y. j& k$ _打造最好的电脑自学交流论坛EternallyConstant beginning execution.
! l" q& L" G- B7 b# fwww.520diannao.com
( \% ]# z1 n! P1 B z! A9 Mwww.520diannao.com打造最好的电脑自学交流论坛 x5 U3 k. V( k2 g
现在试着编辑ChangeALot,修改debug和log变量的值为true(两个都为true)。只重新编译ChangeALot。再次运行EternallyConstant,你将看到下面的输出: 我爱电脑技术论坛7 ?+ {/ @ s$ o. D
我爱电脑技术社区--打造最好的电脑技术自学交流平台7 v5 _! w) ?! q& a2 g( R- v
6 N. \) D" `' W, C! I+ }5 n
EternallyConstant beginning execution www.520diannao.com; D w& R- S- r f v9 B/ H
& t% o# `- M% J7 c我爱电脑技术论坛Logging mode is on 我爱电脑技术社区--打造最好的电脑技术自学交流平台 s# W9 u- L/ F8 o- M
我爱电脑技术社区--打造最好的电脑技术自学交流平台, G+ z, \6 A6 r4 c i+ X
我爱电脑技术社区--打造最好的电脑技术自学交流平台" j2 P" Y2 \0 R" |) m1 D" S) y
debug变量怎么了?即使你将debug设置为true,信息"Debug mode is on"并没有出现。答案在字节码中。对 EternallyConstant运行javap你会看到:
3 j9 d6 w C9 `. u. m: R* g s: _我爱电脑技术社区--打造最好的电脑技术自学交流平台
% [; H* J ^5 {: z+ |" n& a# j电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
) P9 B& w9 i% `* U4 C. mMethod void main(java.lang.String[])
, {& A$ }1 M0 swww.520diannao.com
& t- X4 D% |3 i. y% [; F- rwww.520diannao.com0 getstatic #2 我爱电脑技术社区--打造最好的电脑技术自学交流平台: t% K$ K! t E0 L& O9 @
我爱电脑技术社区--打造最好的电脑技术自学交流平台 o; y6 W1 d5 g4 V2 U, Z% x
3 ldc #3
5 c; x7 o1 y% V+ Z( twww.520diannao.com
; x( ]" _# X4 P) i5 ?我爱电脑技术社区--打造最好的电脑技术自学交流平台5 invokevirtual #4
. k7 L) W; |( t3 p# w7 A我爱电脑技术社区--打造最好的电脑技术自学交流平台5 G7 G( o/ S: n9 [/ m* u$ S* A& @& h
8 getstatic #5
- l- i& R" Q9 @: s6 J! `: g; i/ @0 |我爱电脑技术论坛
' \8 q) Z7 t6 P# W4 S我爱电脑技术论坛11 ifeq 22 www.520diannao.com4 J2 c! U$ ~5 [
+ `2 f( Z9 d" c2 E$ n. ]" kwww.520diannao.com14 getstatic #2 打造最好的电脑自学交流论坛; d1 _) j+ ~+ o O' s3 B' e
; v1 R1 O: h* o' y0 u: \我爱电脑技术论坛17 ldc #6 , h3 w6 m7 h5 e8 x q
打造最好的电脑自学交流论坛5 s* j5 F# m9 n/ J# H
19 invokevirtual #4
; @) B& J9 J% w. x$ Gwww.520diannao.com打造最好的电脑自学交流论坛& }$ A8 p# s1 F& Z0 u! I$ f
22 return 打造最好的电脑自学交流论坛- `0 N1 i" m7 b4 R) T
www.520diannao.com" j& l3 N# ~) S" U7 b9 e+ ?
我爱电脑技术社区--打造最好的电脑技术自学交流平台 K8 d( s7 S3 ]4 N- l$ M5 `
惊奇吧!在log成员上有一个'ifeq'检查,而代码根本没有检查debug成员。因为debug成员被标记为final类型,编译器知道debug成员在运行时永远不会改变,因此它通过移除'if'声明进行优化。这确实是一个非常有用的优化,因为它允许你在程序中嵌入调试代码而在将它设置为false时不用付出运行时的代价。不幸的是这个优化能够导致主要的编译时混乱。如果你改变一个final成员,你必须记住重新编译任何可能引用该成员的类。这是因为这个'reference'可能已经经过优化了。Java开发环境不能总是发现这个微妙的相关性,一些能导致非常奇怪的错误。因此,古老的C++格言对于java环境仍然有效:"When in doubt, rebuild all."(有疑问,重新编译所有的代码)。
0 G' I8 Z/ A$ w5 l" x; r电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站我爱电脑技术社区--打造最好的电脑技术自学交流平台1 b1 N( o% U) r8 t7 j: }3 M) n/ ?
) R2 j. Z) A4 t2 `1 m9 m) S我爱电脑技术论坛知道一些字节码的知识对于使用java编程的程序员都是有价值的。javap工具使得查看字节码很容易。有时候,使用javap检查你的代码以期提高性能和捕获特殊的不易察觉的错误时是没有用的。