java虚拟机随手笔记(7)虚拟机字节码执行引
来源:互联网 发布:订单生成软件 编辑:程序博客网 时间:2024/06/05 18:42
运行时栈帧结构
1栈帧的作用:
2.栈帧的大小:
3.栈帧的结构:
4.局部变量表:
5.方法执行时局部变量表的回收:
placeholder能否被回收的根本原因是:局部变量表中的Slot是否还存有关于placeholder数组对象的引用。 第一次修改中,代码虽然已经离开了placeholder的作用域,但在此之后,没有任何对局部变量表的读写操作,placeholder原本所占用的Slot还没有被其他变量所复用,所以作为GC Roots一部分的局部变量表仍然保持着对它的关联。 这种关联没有被及时打断,在绝大部分情况下影响都很轻微。 但如果遇到一个方法,其后面的代码有一些耗时很长的操作,而前面又定义了占用了大量内存、 实际上已经不会再使用的变量,手动将其设置为null值(用来代替那句int a=0,把变量对应的局部变量表Slot清空)便不见得是一个绝对无意义的操作,这种操作可以作为一种在极特殊情形(对象占用内存大、 此方法的栈帧长时间不能被回收、 方法调用次数达不到JIT的编译条件)下的“奇技”来使用。
6、操作数栈:
也常被成为操作栈,它是一个后入先出的栈。同局部变量表一样,操作数栈的最大深度也在编译的时候写入到Code属性的max_stacks中了。在方法执行刚刚开始id时候,操作数栈是空的,随着执行会有一个一个的数据写入到操作数栈或者出栈。这里存的就是数据了,符号表存的是各种符号(int,double,reference等)。
7,动态连接:
每个栈帧都包含一个指向运行时常量池中该栈帧所述方法的引用,持有这个引用是为了支持方法调用过程中的动态链接。常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就转化为直接引用,这就是静态链接。动态链接是在运行时需要这个变量或者引用是,将符号引用转化为直接引用的过程。
8.方法返回地址:
方法退出的方式只有两种,一种是遇到方法返回字节码,称为正常完成出口(Normal Method Invocation Completion);还有一种退出方式是方法执行过程中遇到异常,并且这个异常没有在方法体内得以处理。一般来说,方法正常退出时,调用者的PC计数器的值可以作为返回地址,栈帧中很可能会保存这个计数器值。 而方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中一般不会保存这部分信息。 方法退出实际上就是栈帧初栈的工作。
9.附加信息:
在实际开发中,一般会把动态链接,方法返回地址与其他附加信息全部归为一类,成为栈帧信息。
方法调用
1.解析:
2.分派:
- 静态分派
我们先看一个面试中经常遇到的例子
上述执行结果为什么将所有的Man和women都当做了Human来执行呢?我们先看这行代码:Human man = new Man();我们这句代码中,Human称为变量的静态类型(static type),或者叫做外观类型(Apparent Type),后面的Man则称为变量的实际类型(Actual Type),静态类型和实际类型在程序中都可以发生一些变化,区别是静态类型的变化仅仅在使用时发生,变量本身的静态类型不会改变,并且最终的静态类型是在编译期可知的,而实际类型变化的结果在运行期才可以确定。编译器在编译一个程序的时候,并不知道一个对象的实际类型是什么。
准确的说,虚拟机在重载时,使用的是参数的静态类型而不是动态类型,于是,就发生了上述情况。
除非你使用强制类型转换。如下所述
sr.sayHello((Man)man);
sr.sayHello((Woman)women);
虽然编译器能确定出方法的重载版本,但是在很多情况下,重载版本不是唯一的,比如各种类型转化,int,char,byte之间的转换。那么这个时候只能确定一种最好的版本,而不是随便一个版本。如下图
我们知道java的类型转换是往安全的方向转换的,也即是说,位数低的朝位数高的转化:
当不能转化时,如果有自己的封装器类存在,比如上述的代码,注释掉int和long之后,就会调用Character,也就是输出Say Character。再注释掉,就会hello Serializable。在注释,就会成为hello Object;再继续注释掉,就变成了hello char...可以看出,这种可变长参数优先级是最低的。
总结下,如果是基本类型,优先是自己的类型,其次是向上转型,再次是包装类,再次是包装类的父类,再次是包装类的接口(如果没有继承,父类和接口不能同时出现),再次是Object,再次是可变长参数。
- 动态分派:
静态分派是和重载同名方法相关的,而动态分派和子类重写父类方法相关的。动态分配很简单,不再多讲。
- 单分派与多分派:
方法的接受者与方法的参数统称为方法的总量。根据分派基于多少总量,可以将分派分为单分派和多分派两种。单分派是根据一个宗量对目标方法进行选择,多分派是根据多于一个宗量对目标方法进行选择。
今天的java语言是一种静态多分派,动态单分派的语言,我们看下面的例子:
- java虚拟机随手笔记(7)虚拟机字节码执行引
- Java虚拟机学习笔记(字节码执行引擎)
- JAVA 虚拟机字节码执行
- 我看Java虚拟机(6)---虚拟机字节码执行
- Java虚拟机(七)虚拟机字节码执行引擎
- 《深入理解java虚拟机》学习笔记(5)--虚拟机字节码执行引擎
- java虚拟机随手笔记(6)虚拟机类加载机制
- 《深入理解java虚拟机》学习笔记——虚拟机字节码执行
- 《深入理解java虚拟机》学习笔记之虚拟机字节码执行引擎
- java虚拟机字节码执行引擎浅析
- Java虚拟机字节码执行引擎浅析
- Java虚拟机之字节码执行引擎
- Java虚拟机--字节码执行引擎
- Java虚拟机字节码执行引擎浅析
- Java虚拟机字节码执行引擎
- JAVA虚拟机字节码执行引擎小结
- Java虚拟机字节码执行引擎
- [Java虚拟机读书笔记]8章 虚拟机字节码执行引擎
- 妙算
- 【codevs1743】反转卡片
- LintCode | 69. 二叉树的层次遍历
- Zend Stuido中安装JSEclipse插件
- matlab学习之一些常用函数
- java虚拟机随手笔记(7)虚拟机字节码执行引
- python的小实验代码的备份,主要偏向于爬虫方向,难点是正则表达式和编码转换[入门]
- 【MyBatis学习07】输出类型resultType及输出参数映射resultMap
- pip的使用和安装
- mysql数据库开始——查询
- ini配置
- Maximum Subarray
- python基础之切片、迭代和列表生成式
- Tegra