|
该用户从未签到
|
java在早期(比如JDK1.2以前)是很慢的,后续版本由于有许多优化手段的加入,Java正变得越来越快,所以现在也有很多关于Java和C/C++孰快孰慢的争论。我想就我自己的理解,谈一下影响Java程序运行速度的因素。% |+ G2 A8 i o5 J2 }0 n# G) k; c
. k# [ F$ I/ S2 n4 l4 n# w' u1、 GC回收
& [) w" r G1 e8 ^- K/ s4 u4 [* D8 a) R; k# Z" a3 A
众所周知,Java相对C/C++的一个很大进步就是有了GC机制,它能够很大程序的避免C/C++常见的内存泄漏的发生。但是这也是有代价的,那就是因为JVM管理了所有内存分配释放,当内存不够时就需要做回收,每次回收都有扫描整个堆,然后要搬移一些内存数据,新生代还好,如果是老年代的GC,会造成程序卡顿一段时间,很多时候是不能接受的,也极大的拖慢了程序的运行速度。虽然GC算法在不断改进,但是也属于只能优化不能根治。
+ J1 ~9 y; x! ]! O& t* P; c4 q
6 S7 L- P$ K- K; Q2、 解释性语言
& T) S8 \7 W( d4 I6 @) L) |4 P W8 R8 |. I7 |
Java为了跨平台,没有直接编译成机器指令,而是编译成字节码,运行时JVM需要加载这些字节码,然后再逐条解释执行。这个过程中,字节码的加载需要时间,然后解释执行也需要时间。做同样一件事情,编译语言可以直接编译成机器码,运行时CPU就直接执行这些指令,而Java是编译成字节码,运行时JVM要把字节码翻译成目标机器的可执行指令,这里面就增加了一层间接性,所以也会降低运行速度。% K5 Q9 |+ p- V( G. s i: q6 Y
+ I. D9 B; C$ ?- s/ ~
3、 JIT消耗资源0 {( T3 Y& b: K0 y2 d& O; m+ Q& k9 _
: r2 h% @3 Z) n& v0 o: VJIT是Java后续版本的改进功能,能把常执行的方法或者语句块即时编译成机器码,这样确实能加快运行速度。但是这种编译是即时发生,会和程序本身抢用运行资源,就会拖慢程序运行的速度。
# @# d5 `9 [9 U0 \4 v n( }, L5 v* P" l) H& M* j9 B4 U5 b7 ]& h d
4、 基于栈的指令集
* r" l. p7 a* c8 d0 e# w" Q0 t2 W' z$ g' R
编译语言多采用基于目标平台寄存器的指令集,这样能充分利用寄存器的高速度。Java为了可移植性,没有绑定某个目标平台的寄存器,而是采用基于栈的指令集。频繁的栈内存访问会导致比较慢的速度,并且通常编译相同语句产生的指令数量也要多于寄存器指令集。
5 U1 g" l; ^; J% \9 A) _
- i0 ]! V) c* i; D, K" e5、 大量使用堆内存) A/ N' L" ~4 L6 x$ B0 w& e
8 D3 a5 [7 ~ `Java中对象创建被JVM托管,能够避免越界或空指针访问之类在C/C++中常见的问题。因此对象大多是创建在堆上的,而不是栈上的,其创建和维护成本上通常要更高一些。9 C# v4 L' @3 T
. s4 @! o$ j. G* k1 f1 o) b
6、 AOT技术6 Q X! m" S/ Y* r
: a7 j6 `3 A$ o8 E6 _
AOT技术能够在字节码安装到目标平台时,先编译成目标平台的执行文件,这样目标平台就可以直接运行可执行文件,速度上可以达到编译类语言的水平。但是这样会导致Java所拥有的动态加载功能丧失,所有字节码都被编译到执行文件,不论其在运行时是否被使用到,并造成其产生的可执行文件相对于字节码来说体积更大。6 |& @' E2 d( f2 S) e& t
# w7 W% X* ~9 Z+ d2 V
总言而之,Java由于其跨平台且管理内存等特性,给开发效率带来了诸多进步,但是凡事有利也有弊,伴随而来的是运行效率的降低。充分了解这些优势和劣势,才能在合适的时候选择合适的技术,以发挥最大的效能。
( e8 B" H/ z% Y+ j1 V
$ Q a" j) p0 `% m o3 a* t8 y7 g(完) |
|