方法内联:
方法内联是编译器最重要的优化手段。它除了消除方法调用成本之外,更重要的意义是为其他优化手段建立良好基础。以下代码就揭示了内联对其他优化手段的巨大价值:没有内联,多数其他优化都无法有效进行。main函数中都是无用代码,如果不做内联,后续即使进行了无用代码消除,也无法发现任务“Dead Coad”的存在。如果分开来看,起始main中调用foo有可能是有意义的。
public static void method(Object obj){
if(obj != null) System.out.println("do。。。。。");
}
public static void main(String[] args){
Object obj = null;
foo(obj);
}
逃逸分析:
逃逸分析是目前Java虚拟机比较前沿的优化技术,它与类型集成关系分析一样,并不是直接优化代码,而是为其他优化措施提供依据的分析技术。
逃逸分析的基本原理是:分析对象动态作用域,当一个对象在方法里面定义后,可能被外部方法所引用,例如作为参数传递到其他方法中,这就是方法逃逸;甚至还有可能被外部线程访问,譬如赋值给可以在其他线程中访问的实例变量,这种成为线程逃逸;从不逃逸到方法逃逸、线程逃逸,称为对象由低到高的不同逃逸程度。
栈上分配:
在Java虚拟机中,Java堆上分配创建对象的内存空间几乎是Java程序员人人皆知的常识,Java堆中的对象对于各个线程都是共享可见的,只要持有这个对象的引用,就可以访问到堆中存储对象数据。虚拟机的垃圾收集子系统会回收堆中不再使用的对象,但回收动作无论是初始标记,还是回收和整理内存,都需要耗费大量资源,如果确定一个对象不会逃逸出线程之外,那让这个对象在栈上分配内存也是一个不错的注意,对象所占用的内存空间就可以随着栈桢出栈而销毁。在一般应用中,完全不会逃逸的局部对象和不会逃逸出线程的对象所占的比例是很大的,如果可以栈上分配,那大量的对象都会随着栈桢出栈而销毁,垃圾收集子系统的压力会下降很多。栈上分配可以支持方法逃逸,但不能支持线程逃逸。
标量替换:
若一个数据无法在分解更小的数据来表示,Java虚拟机中原始数据类型(int、long等数值类型以及reference类型等)都不能再进一步分解了,那么这些数据就可以被称为标量。相对,如果一个数据可以继续分解,那它就称为聚合量,Java中的对象就是典型的聚合量。如果把一个Java对象拆散,根据程序访问的情况,将其用到成员变量恢复为原始类型来访问,这个过程就称为标量替换。假如逃逸分析确定一个对象不会被方法外部访问,并且这个对象可以被拆散,那么程序正在执行的时候可能不去创建这个对象,而改为直接创建它的若干个被这个方法使用的成员变量来替换。对象拆分后,除了可以让对象的成员变量在栈上(栈上存储的数据,很大机会被虚拟机分配至物理机器的高速存储器中存储)分配和读写之外,还可以为后续进一步的优化手段创造条件。标量替换可以视作栈上分配的特例,实现简单,但对逃逸程度的要求更高。他不允许对象逃逸出方法范围内。
同步消除:
线程同步本身就是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程也就是无法被其他线程访问,那么这个变量的读写肯定就不会有竞争,对于这个变量实施的同步措施也可以完全地消除。