JVM Specification Note-1

原来虚拟机还有一个返回值的类型,returnAddress

在帧中的本地变量中,其变量的内存都是编译时就分配的,在存放在一个数组中.
其中有趣且熟悉的是,LongDouble类型的变量会占两个坑,就是说,在LocalVaraiable[]中,需要用两个Index来存放一个元素,可想到,这就是C中的数组啊,一个元素是32位。而LongDouble都是64位的,所以,一切在不言中。
最近看了Python的语法,看到每个方法前面都要写一个self,而在java中就是this的意思,每一个方法的调用,都要传递调用者作为第一个参数,因而,调用一个方法,就有两种形式了:

	instance.foo(parameters...)
	Class.foo(instance,paramters...)
	

回到这个帧的本地变量,原来LocalVaraiables[0]就默认指定了当前实例中的this。之后就是参数来了。


Oparand Stack 操作栈

在每一帧中都会存在一个栈,当context 确定后,即该帧在正在被操作时,就简单地把这个帧中的栈称之为操作栈了。
没看懂一个帧中的栈会在编译时就能确定深度?
额,打出这句疑惑时好像明白了。
开始的疑惑归咎于?

将方法和帧的概念混淆了。
方法可以有嵌套,若是递归,编译时怎么会知道要多少次,这个栈并不是简单的对应的每一个方法,
帧是比方法更小的单位。
大概就先理解到这了。

操作栈的大致的情况就是,有一个context,丢几个进去,返回一个东西。比如add(x,y),先入x,y,来一个操作符add,计算,将x,y丢出来,将结果入栈保存。

发现有点看懵,前面的概念没有弄清,重新梳理下运行时的数据储存区。

Run-Time Data Area 运行时存储区

首先先分两个点,java程序启动后,作为一个进程,启动后有一个公共的数据区,作用域为进程,而另一个小范围的是一个线程作用域的。

the pc Register pc寄存器

因为要支持多线程嘛,所以每个线程是分配有一个存放PC寄存器的。PC寄存器就是用来记录当前程序到指令位置,若是当前运行的java方法,则PC保存java程序正在执行指令的位置,若是执行的是native方法,那么其保持的值是undefined。不知道为啥,最后又来一句,The JVM’ pc register is wide enough to hold returnAddress or a native pointer on the specific plaform.

JVM Stack (以前叫做Java stack)

这个Java stack会在线程创建时创建,并在在其中保存很多个帧(frame)。 类似C语言中的Stack,会持有本地变量,部分结果,用于方法调用和返回。这个栈的操作单位是frame, 将其入栈出栈。

帧和栈的关系呢?

栈可以固定,或是动态的(即可以配置最小和最大范围)。

Heap

堆是在java虚拟机启动后创建的,即其作用域是跨过所以线程的,这也就是为什么要多个线程访问一个对象时需要加锁的原因了。其保存的包括对象以及数组。
如栈一样,同样可以fixed或dynamic.

Method Area

方法区也全线程共享的。
存放的内容包括编译后的字节码,以及一些text.
存放类的结构,包括:

  • run-time constant pool 运行时常量池
  • field 域,变量
  • method data
  • the code for methods android constructions

看起来就是存放我们的代码指令,一般不会变动太大,所以有的选择作为堆的一部分。或者单独拿出来,因为变动不是很大。

Run-Time Constant Pool

常量池是classinterface中constal_pool table中包含的,包括numbers iterails andfiled refrences.这个域引用,会在运行时被解析,指向确定的对象实例。
嗯,它还说,就类似往常的编程语言中的符号表symbel table。(然鹅,我对常见编程语言没概念啊~)

这里,这个还指出了:常量池跟之后要重点学习的,loading,linking, initailizing关系大大的。

Native Method Stack

为了支持Native方法了,调用本地方法就滚到这个栈去了。

2.6 Frame

这个重要,一个帧会在一个方法调用时创建,并在结束时销毁。里面涉及到几个概念。

  • Local Variables
  • Operand Stack
  • Dynamic Linking
  • Nomal Method Invocation
  • Abrupt Method Invocation
本地变量

在编译时就确定其长度,并保存在字节码中。
作为一个数组来保存这些变量,其值类型很有趣:
数组元素是32位,单个元素可保存boolean,byte,char,short,int,float,reference, or returnAddress.
用两个坑保存Long或Double.
在调用方法时,使用本地变量来传递参数的,第一个元素是调用该方法的对象的引用。之后才是其他参数。

猜想,既然本地变量存在一个returnAddree,那个一个方法签名中也包括返回值类型,那么在方法调用完成后,便把结果赋予返回值得中。即完成了结果返回。

Operand Stack 运算元栈

每一个帧中包含栈又叫做operand stack.

对之前的疑惑更清楚了一点,为什么在编译时,这个栈的深度就确定了。
这个栈在在frame是在调用到该方法时,即context is clear。
用来准备要传递的数据,以及接受结果。
这是真正的运行,会有专门的指令将数据,操作符入栈,出栈。执行最细节的操作。
如,开始开始描述的。。

Dynamic Liking动态链接

根据个人理解,一个Class中定义的仅是一个方法要做的动作。而这个动作的执行者在这个动作定义中是没有确定的,所以动态链接就是要确定这个执行者具体是谁。当然还包括,形参到实参的转变,。

方法正常结束

解释很正常,无异常结束该方法调用。(包括返回其预期想要的结果类型)
若是当前frame是用来,restore the state of invoker, including its local variables and operand stack. PC可能会直接跳过方法。。

(好吧,不理解…) 难道是break ?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值