JVM规范(四)Frames

Frames

一个frame是被用于存储数据和部分结果的,以及执行动态链接、返回方法的值和分派异常。

frame在每次一个方法被调用时创建,在方法调用结束时销毁,不管其完成的结果是正常的还是异常的。frame从创建此frame的线程的虚拟机栈分配。每个含有它自己的本地变量数组、它自己的操作栈和当前方法的类的运行时常量池的引用。

frame本地变量数组和其操作栈大小在编译时确定,且同此frame相关联的代码一起被提供。因此frame数据结构的大小仅依赖于Java虚拟机的实现,些数据结构内存基于方法调用同时被分配。

在一个给定的线程中,任何时候都仅有一个frame(针对正在执行的方法的frame)处于活动状态。这样的frame被称为current frame,它的方法被称为current方法,它的方法所在的类被称为current class,对于局部变量和操作栈的操作通常会使用current frame的引用。

如果一个方法调用了另一个方法或者当前方法调用完成,那么frame将不再是当前的(不再是current frame)。当一个方法被调用时,一个新的frame就会被创建并且在控制权转换给这个新方法时成为当前的(current)。当方法返回时,current frame回传方法调用的结果,如果有的话,就传给上一个frame(previous frame),这时current frame就会被废弃,previous frame则变成当前的。

值得注意的是被一个线程创建的frame是属于那个线程的私有的,不能够再被其他线程引用。

Local Variables(局部变量)

每个frame都包含了一个局部变量的数组。一个frame的局部变量数组的长度是由编译时确定的,以一个类或者接口连同与此frame相关联的方法的代码的二进制表示提供。

一个单一的局部变量其值类型可以是boolean byte char short int float reference 或者 returnAddress。一对局部变量其值可以是long或者double类型。

本地变量是通过编入索引中来编址的。每一个局部变量其索引为0,如果一个整数在0与局部变理数组大小之间,均可作为局部变量数组的索引。

long或者double类型的值独占相连两个局部变量,这种值可能使用较小的索引编址。比如,存储在局部变量数组中索引N处的的一个double类型的值实际占据N和N+1两处局部变量位置,但是不能使用N+1索引到此double值,可以在N+1位置存入局部变量,但这意味着作废了N处的局部变量。

Java虚拟机并没有要求N一定是偶数。更直观的说,局部变量数组中的long或者double类型的值并不需要64bit对齐。实现者可自由的决定恰当的方式来通过使用两个局部变量来表现这样的值。

Java虚拟机使用局部变量在方法调用时传递参数,在类方法调用时,所有的参数都是以连续的局部变量的形式传递的,从0索引开始。在实例方法调用时,0索引处的局部变量通常用于传递一个对象(被调用方法所在的对象)的引用。随后的所有参都是以连续的局部变量传递,从索引1开始。

Operand Stacks(操作数栈)

每个frame都包含了一个后进先出的栈,即为它的Operand Stack。一个frame的Operand Stack的最大深度是由运行时决定的,其伴随与frame相关联的方法的代码被提供。

在上下文环境中,有时我们使用current frame的Operand Stack作为简单的Operand Statck。

当frame被创建时,它的Operand Stack是空的。Java虚拟机提供指令来加载常量或者局部变量或者域的值到Operand Stack。别的虚拟机指令从Operand Stack提取操作数,对它们进行操作,然后将结果放回到Operand Stack。Operand Stack也用于预备传递给方法的参数和接收方法返回的结果。

例如,iadd指令同时添加两个int类型的值,它要求被添加的int类型的值添加到Operand Stack的顶部。在执行时,两个被添加的int类型值都会从Operand Stack弹出,如果是加法操作,那么它们的和将会被返回且添加到Operand Stack的顶部。子计算指令可能内嵌到Operand Stack上。

Operand stack的每一入口都支持Java虚拟机的所有类型的值,包括long类型的值和double类型的值。

从Operand stack提取的值的操作都要基于它们的操作类型。例如,不能添加了两个int类型的值,但随后把它们当long类型对待,或者添加两个float类型的值时使用iadd指令。少量的虚拟机指令(dup指令和swap指令)只把运行时数据区域的数据作为原始数据值操作,而不考虑它们的类型,如此方式定义的虚拟机指令都不能用于修改或者破坏数据值。所有在Operand Stack上的操作的限制都地class文件验证阶段实施执行。

任何时候,一个Operand Stack都关联着一个深度值,long或者double占两个单位的深度值,其他类型占一个。

Dynamic Linking(动态链接)

每个frame都包含一个当前方法类型的运行时常量池引用,以支持方法代码的动态链接。一个方法的class文件代码指的是被调用的方法和通过符号引用被访问的变量。动态链接将这些符号的方法引用转换为具体的方法引用。按需加载类以解决至今尚未定义的符号,转换变量访问为这些变量的运行时位置相关联的存储结构的适当偏移量。

方法和变量的后期绑定在其他类中做出改变,以便一个方法的使用不会破坏这些代码。

Normal Method Invocation Completion(正常方法调用结整束)

如果一个方法调用没有引起抛出异常,包括虚拟机抛出或者执行了明确的throw语句,那么即为方法调用正常结束。如果当前方法调用正常结束,可能会返回给些方法调用都一个值,此种行为发生在当被调用方法返回指令中的一个时,返回指令的选择要依赖于被返回值的类型。

current frame就是这种情况下被用于恢复调用者的状态,包括它的局部变量和Operand Stack(操作数栈),通过调用者的程序计数器(pc,program counter)恰当的增加来跳过方法引用指令。然后这个调用方法的方法继续执行。

Abrupt Method Invocation Completion(意外方法调用结束)

一个方法调用意外结束即方法调用过程中发生了异常,而当前被调用方法未曾捕获处理使得方法调用意外结束。意外方法调用结束有会给调用者返回值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值