唉~~因为blog总显示不全只能分为2个了,排版也不是很好,凑合着看吧。
客户端执行的优化策略有如下3种措施
方法内联:一个方法的执行离不开其他方法的支持,若调用的其他方法十分简单。那么调用的时候会将被调用那个方法里面所有的内容粘到主调方法中,这样做的好处是节省参数变量,中间变量的资源和返回值的资源申请位置。
??? private void test(){
?????? test2("1");
??? }
???
??? private String test2(String a){
?????? //test2的方法体
?????? return null;
??? }
在JVM编译中会变成如下方式
??? private void test(){
?????? //test2的方法体
??? }
去虚化处理:装载类的时候会进行类层次的分析,如果发现接口的方法是有一个实现类,那么JVM会说,别故弄玄虚了,就那么一个实现类,咱将实现类的方法实现内容全粘过来才是实在人,做人要厚道。
接口如下
public interface IA {
??? public void t();
}
实现类如下
public class A implements IA {
??? public void t(){
?????? //做你想做的事情
??? }
}
下面是一个客户端调用类
class Demo{
??? public void execute(IA ia){
?????? ia.t();
??? }
}
那么JVM去虚化会将此代码替换成
class Demo{
??? public void execute(IA ia){
?????? //做你想做的事情
??? }
}
冗余消除:冗余消除是在编译期间发现代码可以进行折叠或者消除。
比如如下代码
public class A implements IA {
??? final static boolean isDebug = false;
??? public void t(){
?????? if(isDebug){
?????????? System.out.println("容我三思");
?????? }
?????? System.out.println("全线出击");
??? }
}
反编译后的class内容如下
import java.io.PrintStream;
?
public class A
? implements IA
{
? static final boolean isDebug = false;
?
? public void t()
? {
??? System.out.println("全线出击");
? }
}
编译期间可以确定代码不会执行到“容我三思”的步骤,您只能“全线出击”。
服务器模式编译则比客户端模式编译更加费资源,因为编译器模式的很多优化策略是从整体类运行出发的,主要优化点是标量替换、栈上分配、同步消除三项。这三项优化措施都是基于分析变量是否逃逸的分析结果。这些我们知道有这么个事情,了解一下即可,因为咱们还没到开发JVM的程度。
3):反射执行:
先回顾一下反射的代码,再来看看JVM如何处理反射执行的过程的
?????? Class cls = Class.forName("java.lang.String");
?????? Object obj = cls.newInstance();
?????? Method method = cls.getMethod("valueOf", Object.class);
?????? String str = (String) method.invoke(obj, 1);
?????? System.out.println(str);
反射调用实际就是动态生成字节码,并加载到JVM中进行执行。流程如下:先让调用者所在的ClassLoader来加载创建Class对象,Class对象生出来了,之后校验Class是否为public权限的,如果不是,那么对不起,反射机制在伟大也不能违反原则,越雷池一步,不是public的类,您还是少碰为妙!之后JVM调用对象的newInstance方法,,该方法先去查找是否有缓存的ConstructorAccessor对象,如果没有则生成一个。生成ConstructorAccessor的过程需要MethodAccessorGenerator中的generate方法根据Class格式规范生成字节码,在生成字节码后,将其加载到ClassLoader中,并实例化完成对象的创建过程。之后就是寻遍方法数组,对照有没有要使用的”valueOf”方法,如果没有则抛出异常。如果有,则验证权限是否能暴露出来供反射调用,所以也是为什么反射调用执行稍微比直接对象调用方法有点慢的原因了。它需要验证使用权限,还要负责创建Method对象。传说是现在的JDK版本(Sun JDK1.6.26)在直接调用和反射调用的性能差别不大。这个笔者并没试过,改天有时间再做测试。
5.? 总结
JVM内容很多,这次仅仅介绍了JVM编译、执行java代码的过程,类加载过程因为之前做过总结(http://suhuanzheng7784877.iteye.com/blog/964784)。了解了JVM编译,加载、执行的过程,以后我们写代码脑子里就多一层过滤,这是一种潜移默化的。JVM还有很多其他相关内容,比如JVM内存回收机制,也在笔者的blog:http://suhuanzheng7784877.iteye.com/blog/1000646做过相应的总结。在此不再赘述了。
?