在完成将class文件信息加载到JVM并产生class对象之后,就可以执行Class对象的静态方法或者实例方法对对象进行调用了。JVM在源代码编译阶段将源代码编译为字节码文件,字节码是一种中间代码的方式,要由JVM在运行时进行解释执行,这种方式称之为解释执行方式。

1、字节码的解释执行

SunJDK是基于栈的体系结构来执行字节码的,基于栈的好处是代码紧凑,体积小。每个线程创建之后,都会产生一个程序计数器(又称PC计数器)和栈,栈中存在若干的栈帧,每个方法的调用都会产生栈帧。栈帧主要包含两部分,局部变量和操作数栈,局部变量用户存放方法中的局部变量和参数,操作数栈用于存放方法中性过程中产生的中间结果,栈帧中还会有一些杂用的空间,用于存放指向方法已解析的常量池的引用,一些JVM内部所需要的数据等。如下图所示

1)指令解释执行

方法的指令执行是经典的冯诺依曼体系中饿FDX的循环方式,即取一条指令,然后分派,执行。如下面的代码

while(true){int code=fetchNextCode();switch(code){case IADD:// do addcase …:// do sth.
           }}

以上程序很简单的满足了我们的需求,也是FDX循环模式一个很简单的实现,但是这段程序每次执行完毕都会回到程序的原点,重新判断重新执行,效率是比较差的,所以,有人提出了一种叫token-threding的方式,使用令牌来进行处理,如下面的代码

IADD:{// do add;
       fetchNextCode();dispatch();}ICONST_0:{//do sth
       fetchNextCode();dispatch();}

这段代码冗余了fetchNextCode和dispatch两条指令,性能相对会好一些(为什么性能会好?详情请参看博文JAVA类的执行机制)但是使用这种方法由于冗余相关指令,因此占用的内存会大一些。

2)  栈顶缓存

在方法执行过程中,可以看到有很多重要的操作将数据放入到操作数栈,这会导致寄存器和内存要不断的进行交换数据,SunJDK采用可栈顶缓存,即将本来位于操作数栈的值直接缓存在寄存器上,这样对于大部分只需要一个操作数的操作而言,无需将数据放入操作数栈,可直接在寄存器上进行计算,然后放回操作数栈。

3)  部分栈帧共享

当一个方法调用另外一个方法的时候,通常会传入另一个方法的参数存放在操作数栈,SunJDK为此做了一个优化,就是当调用方法时,后一方可以将前一方的操作数栈作为当前方法的局部变量,从而节省数据copy带来的损耗。

当然SunJDK为了提高数据执行的效率,做了很多优化,这里有不一一列举了。

2、编译执行

解释执行的效率是很低的,为了提升代码编译的执行性能,SunJDK也提供了编译执行的机制(N多教科书上说java是一种解释型语言,都是不全面的,JVM是可以执行编译执行的),编译在运行时进行,通常成为JIT编译器。SunJDK对执行频率高的代码进行编译,而对执行频率不高的代码仍然进行解释执行,因此SunJDK又被称作为HotspotVM,对于编译,SunJDK提供了2种方式,clint complier(-clint)和server complier(-server)。

Clint complier又被成为C1,较为轻量级,只做少量的性能开销比较高的一些优化,占用内存较少,适合做桌面的交互式应用。在寄存器分配策略上,JDK6采用了线性扫描寄存器的方式(具体可参照http://www.bluedavy.com/book/reference/LSRA.pdf),在其他方面的优化主要包括:方法内联、去虚拟化、冗余消除等!

1) 方法内联

对于java语言来说,通常需要调用多个方法来完成功能,执行的时候还需要多次传参和返回值传递,因此C1采用了方法内联的方式,把用到的方法直接植入到当前的方法中,示例如下

public void buy(){saveOrder();saveDetail();}public void saveOrder(){//do save saveOrder
    }public void saveDetail(){//do write detail}

当编译的时候,发现编译后的buy方法的字节码≤35个字节(这个可以通过JVM启动的时候设置参数-XX:MaxInlineSize=35来进行控制),则该程序会演变成下面的结构!

public void buy(){//do save saveOrder//do write detail
}

2)  去虚拟化

去虚拟化是指在状态class文件之后进行层次分析,如果发现类中的方法只提供了一个实现类,那么对于条用了此方法的代码,也就可以通过方法内联来提高性能。如下列代码

interface OrderInterface{public void buy();
}
class Order implements OrderInterface{@Overridepublic void buy() {//do buy
  }
}
public class Test{public void testBuy(Order order){order.buy();}

当JVM在编译的时候发现buy方法只有一个实现的时候,就演变成以下结构

public class Test{public void testBuy(Order order){//do buy
       }
}

3)  冗余消除

冗余消除是指在编译时,根据运行时的状况进行代码折叠或削除,如下代码

import com.sun.org.apache.commons.logging.Log;
import com.sun.org.apache.commons.logging.LogFactory;
public class Test{private final static Log log = LogFactory.getLog(Test.class);private final static boolean isDebug = log.isDebugEnabled();public void execute(){if(isDebug)log.debug("Test.execute() has been excuted");//do sth
    }
}

这段代码在编译的时候如果被监测到isDebug是false,则执行完C1编译之后就变成了如下代码

public class Test{public void execute(){//do sth
    }
}

这也是很多时候优秀的程序员不直接写log.debug而要先写一个判断的原因。

Server complier又称为C2编译,就比较重量级,这个我们下次再讲。今天先到此吧,休息一下,哈哈!

深入理解JVM--类的执行机制相关推荐

  1. 深入理解JVM之代码执行机制与线程资源同步及交互机制

    Java规范定义标准结构如图3.1 Java代码的执行机制 Java源码编译机制 javac将Java源码编译为class文件的步骤如图3.2 1.分析和输入到符号表(Parse and Enter) ...

  2. jvm垃圾回收机制_深入理解JVM的垃圾回收机制

    ​如何判断对象已"死" Java堆中存放着几乎所有的对象实例,垃圾回收器在堆进行垃圾回收前,首先要判断这些对象那些还存活,那些已经"死去".判断对象是否已&qu ...

  3. 【深入理解JVM】ClassLoader类加载机制

    Java程序并不是一个原生的可执行文件,而是由许多独立的类文件组成,每一个文件对应一个Java类.此外,这些类文件并非立即全部装入内存的,而是根据程序需要装入内存.ClassLoader专门负责类文件 ...

  4. spi 动态加载、卸载_理解 ServiceLoader类与SPI机制

    对于Java中的Service类和SPI机制的透彻理解,也算是对Java类加载模型的掌握的不错的一个反映. 了解一个不太熟悉的类,那么从使用案例出发,读懂源代码以及代码内部执行逻辑是一个不错的学习方式 ...

  5. fegin需要实现类_深入理解JVM(六)--虚拟机类加载机制

    虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类从被加载到虚拟机内存开始,到卸载出内存为止 ...

  6. 深入理解JVM(5)——虚拟机类加载机制

    在Class文件中描述的各种信息,最终都需要加载到虚拟机中之后才能运行和使用.而虚拟机中,而虚拟机如何加载这些Class文件?Class文件中的信息进入到虚拟机中会发生什么变化?本文将逐步解答这些问题 ...

  7. 深入理解JVM类文件格式

    我们知道Java最有名的宣传口号就是:"一次编写,到处运行(Write Once,Run Anywhere)",而其平台无关性则是依赖于JVM, 所有的java文件都被编译成字节码 ...

  8. java 执行机制_Java类的执行机制

    在完成将class文件信息加载到JVM并产生Class对象后,就可执行Class对象的静态方法或实例化对象进行调用了.在源码编译阶段将源码编译为JVM字节码,JVM字节码是一种中间代码的方式,要由JV ...

  9. 深入理解JVM之虚拟机类加载机制

    1.概述 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制.与那些在编译时需要进 ...

  10. vuex 的理解,vuex 的执行机制

    vuex 是 vue 的状态管理工具 管理项目中的公共数据 能够在所有的组件中使用 vuex一共有五大核心: state 存放公共数据的地方 通过 this.$store.state.xxx调用 mu ...

最新文章

  1. 超硬核的 Python 数据可视化教程!
  2. 面试题整理12 求字符串括号最大深度子串
  3. linux 命令综述
  4. HttpClient-01基本概念
  5. .net 从txt中读取行数据_【VBA项目】从指定文件中读取数据并绘制图表
  6. oracle+semijoin,Semi join 与anti join
  7. 洛谷1008 三连击
  8. 宜普电源转换公司(EPC)于2018年WiPDA宽能隙功率器件及应用论坛与工程师作技术交流
  9. P1179 数字统计
  10. 北京迷笛音乐节阵容、北京草莓音乐节阵容
  11. 悲情陨落的十大民族品牌
  12. vue项目中页面打印插件(去除页眉页脚)
  13. 2019年肖秀荣命题人精讲精练
  14. 【个人向】《春物》 小说原文关键段落摘录
  15. Driller分析与改进(二)
  16. 方差、协方差、协方差矩阵以及互相关矩阵
  17. 4路编码器脉冲计数器,转速测量,8路DO,Modbus TCP数据采集模块
  18. Centos7安装Mysql(yum 安装)
  19. 2022-2028全球机载温度传感装置行业调研及趋势分析报告
  20. 周杰伦《说好不哭》:眼泪流完,青春也就结束了

热门文章

  1. 创建WPF单实例应用程序
  2. AJAX,JSON与MVC
  3. 07-02 测试报告-allure
  4. android runnable内存泄漏,这个Runnable可以防止内存泄漏吗?
  5. 使用aws跑深度学习_RNN示例项目从开发到部署(三):在AWS上部署深度学习模型...
  6. html判断用户名的合法性,javascript简单判断输入内容是否合法的方法
  7. python最大的社区_python 最大流
  8. 2020年前端如何适应大环境,发展的前途与趋势是怎么样的?
  9. cookielifetime php_PHP session有效期session.gc_maxlifetime的设置方法
  10. ipad导入pdf_Ipad笔记法①日常笔记篇