深入理解java虚拟机-jvm执行引擎(8)

java虚拟机规范定义了虚拟机执行字节码的概念模型。

通俗的说就是,输入java字节码,对字节码进行解析,得到执行后的结果。

这个就不得不提,运行时栈帧的结构了,在java的中,栈帧是java方法调用的的数据结构,每个方法的调用都伴随一个方法的入栈出栈。

局部变量表:

局部变量表就是用来存储,栈帧调用过程中的各个数据,单位为slot(槽),long,double占用两个slot,其余的基本类型

和引用类型都占用一个slot,实例方法中slot 0就是当前对象的引用指针的地址 即this,并且slot是可以复用的,

当程序计数器的指示值超过,某个变量的范围的时候,这个slot可以被其他变量复用的。

public class SlotRepeat {

	/**
	 * 虚拟机参数,-verbose:gc
	 */
	public static void main(String[] args) {
		gc3();
	}

	/**
	 * 运行结果,发现调用gc的时候 并没有回收  System.gc();会发生full gc,
	 * [Full GC (System.gc())  103056K->102999K(226816K), 0.0159223 secs]
	 */
	private static void gc1() {
		byte [] b = new byte[1024*1024*100];
		System.gc();
	}
	
	/**
	 * 运行结果,发现调用gc的时候 还是没回收
	 * 这个时候b已经不再作用域了为什么还没回收呢?
	 */
	private static void gc2() {
		{
			byte [] b = new byte[1024*1024*100];
		}
		System.gc();
	}
	
	/**
	 * 干啥了,居然回收了,加了个int a =1;
	 * 这是因为虽然b不再作用域了,但是当前slot仍然存在引用,并没有被覆盖,会在清除,
	 * 扫描gcroot的时候 仍然会把他党委可用的引用,当进行a=1的时候slot的值被覆盖,
	 * 则可用进行回收了
	 */
	private static void gc3() {
		{
			byte [] b = new byte[1024*1024*100];
		}
		int a =1;
		System.gc();
	}

 

操作数栈:

操作数栈是一个新进后出的数据结构,在进行非法调用的时候,会有各种java字节码指令对操作数栈进行读入和写出数据,

即入栈,出栈,算术运算也是通过操作数栈来完成的

动态链接:

每个栈帧都持有当前方法在常量池的引用,是为了支持方法调用的动态链接(dynamic linking)

之前学习类的解析阶段的时候,会把常量池的符合引用转换为直接引用,对于解析方法调用,有一个前提条件,就是

这个方法必须是唯一确定的,并且该方法是运行期不可改变的,也就是方法必须在编译阶段就确定了方法调用的版本

,这样的方法有 构造方法,私有方法,静态方法,都是可以确定唯一方法的。

 

静态分派,根据静态类型的分派,在编译阶段就知道了调用那个重载方法了。

public class StaticDispatcher {

	
	public static void main(String[] args) {
		new StaticDispatcher().eat(new StaticDispatcher().new Human());
		new StaticDispatcher().eat(new StaticDispatcher().new Student());
	}
	
	 void eat( Human human){//这个地方的Human就是静态类型,编译时期可知
		System.out.println("Human eat");
	}
	
	 void eat( Student student){//这个地方的Student就是静态类型,编译时期可知
		System.out.println("Student eat");
	}
	
	 class Student extends Human{
	}
	
	class Human{
	}
}

也有一些方法是在运行时期决定实际调用的方法的。

这个就是java特性之一了 多态,也就是子类方法重写,

这个是在运行期决定方法的调用者。

1,首先在当前局部变量的slot中第0个变量加载栈顶

2,根据当前对象的方法描述和简单名称进行匹配,并且进行访问权限检查(private public ),如果通过则返回当前方法的直接引用,进行调用

3,如果上面匹配失败,则到其父类进行方法的匹配,还匹配不了就是 抛出异常

 

public class DynamicDispatcher {

	
	public static void main(String[] args) {
         //在编译时期是不知道具体的方法调用的,只有在运行期才知道具体方法的调用,
        //虚拟机实际上是不会进行如此频繁的,由子类到父类
		 Human human  = new DynamicDispatcher().new Student();
		 human.eat();
		 Human human1  = 	new DynamicDispatcher().new Human();
		 human1.eat();
	}
	
	 class Student extends Human{
		 void eat( ){
			 System.out.println("Student eat");
		 }
	}
	
	class Human{
		void eat(){
			System.out.println("Human eat");
		}
	}
}

 

方法返回地址

即方法调用返回给调用者的地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值