|Practical Java| Chapter 4 Performance (性能) (二)
35> 尽可能使用 Stack 变量
JVM是一种 Stack - based 虚拟机, 因此在访问和操纵 Stack data时性能最
佳. 程序中所有的 local 变量都会被放在一个local 变量表中, 并于Java
operand 中操纵, 从而获得很好的性能.
而访问static 变量或者 instance 变量的代价则高出许多, 因为JVM不得不
使用更耗时的 opcode, 从constant pool(常量池)中访问她们.
constant pool ----> 保存着 symbolic references, 指向所有型别 / 值域, 以
及每一个型别所使用的所有方法.
36> 使用static / final 和private 函数以促成 inlining
为了让函数成为 Inlining 候选者, 必须将她们声明为private / static 或者
final. 此类函数可以被 statically resolved, 而不是dynamic resolution.
同时也存在一些缺点: 这些函数无法通过subclassing 进行扩展.
当一个函数inline 后就不再需要负担函数调用的额外开销, 所以在被多次
调用的情况下, 其性能的提升越明显.
37> Instance变量的初始化一次就好
对于面向对象系统而言,程序很多时间都花在对象的creating 和destroying
上, 因此让construct 尽可能高效对程序十分有益.
Java对于 Instance 变量 / static 变量 和 arrays 都进行了缺省的初始化工作.
(default initialization). Local 变量是没有缺省值的, 必须为其明确初始化, 只
有class 的static变量和instance 变量才有缺省值.
38> 使用基础类型(primitive Types )使代码更快更小
小型基础类型(short / byte / char / boolean)存储于 Stack 上或用于局部
变量时, 通常被提升为int , 以4bytes 存储.
使用 primitive Types 时在速度和存储空间上比之类对象或者wrapper对
象都更好, 但当用到 Java collection classes时必须用对象, 因为群集类都
只管理 java.lang.object 对象.
39> 不要使用 Enumeration 或 Iterator 来便利 Vector
Java提供了便利 Vector 元素的几种方法:
A> Iterator (迭代器); //次次之;
B> ListIterator (List 迭代器); //次次之;
C> Enumeration (枚举器); //次之;
D> get() 函数; //性能最高;
40> 使用 System.arraycopy() 来复制 arrays
函数调用代价确实高昂, 但也有例外; 比如array 的复制.
由于 System.arraycopy() 是以本机函数 (native Method)实现的, 因此她的
执行速度比之for循环中的赋值操作要快. 同时也由于她是一个本
机函数, 所以这个调用动作的执行速度在不同平台上有所不同.
41> 优先使用 Array, 然后才考虑 Vector 和ArrayList
由于 Vector 和ArrayList 都涉及对象操作, 所以 Array 会比她们两个快很
多, 其中由于Vector 函数的synchronized , 她会比ArrayList 慢.
V / A 都支持在需要时自动调整本身体积, 都采用array 作为底部设施, 所
以当这些classes 调整自身大小的时候,会创建一个新的array, 然后将所有
的元素从原来的array复制到新的array 中.
42> 尽可能复用 ( reuse) 对象
对象的复用比之对象的重复创建, 其性能有所优化, 但如果调用函数要
保存的是 Object reference则 reuse 是不能用的.
44> 以手工方式优化代码
(javap -c PP > pp.bc disassemble class File and save it in pp.bc);
优化技术:
A> 删除空白函数 (Empty Method removal);
B> 删除无用代码 (Dead code removal );
C> 削减强度 (Strength reduction);
D> 合并常量 (Constant folding);
E> 删除相同的子表达式 (common subexpression elimination);
F> 展开循环 (Loop unrolling);
G> 简化代数 (Algebraic simplification);
H> 移动循环内的不变式 (Loop invariant code motion);
45> 编译为本机代码 (Compile to native code )
在牺牲Java 的平台可移植性 (platform portability) 的情况下可通过将 Java
源码编译为本机二进制码 (native binary code)以提高性能. 这种做法并不
是把Java 源码编译为 bytecode形式,而是直接编译为本机机器指令 ------
( native machine instructions);
这样在运行期将不再为 bytecode --> native code 付出额外代价.
(static code generation ) 静态代码生成方式可以实现上述情况, 只是得放
弃跨平台性. 如果你的代码只要求在一种机器上运行 , 如服务器应用
程序编码 / 嵌入式设备 (embedded device)编码时是不错的选择.
当代码编译为 native binary code , 没有了JVM 的协助, 此时垃圾回收机制
怎么工作那?
------ 不同厂商对这个问题的答案不尽相同.
A> 在目标系统上部署一个小型虚拟机, 不需要操心内存管理;
B> 增加一个delete关键词到她们的Java-like 语言中.不过这样 添加了
不属于Java语言规范的东西,无法移植到兼容实现品上;
C> 在维持Java 平台移植性的同时, 将程序的某些部分编译为本机
二进制代码.