每一个Java程序都运行于自己的Java虚拟机实例中
每一个java虚拟机实例都一个方法区和堆,装载class文件时,会将class文件中包含的二进制数据中解析类型信息放到方法区中,将所有程序在运行时创建的对象放到堆中
方法区
类型信息和类的静态变量都存储在方法区中。方法区中对于每个类存储了以下数据
a.类及其父类的全限定名(java.lang.Object没有父类)
b.类的类型(Class or Interface)
c.访问修饰符(public, abstract, final)
d.实现的接口的全限定名的列表
e.常量池
f.字段信息
g.方法信息
h.静态变量
i.ClassLoader引用
j.Class引用
新线程创建时,被分配PC寄存器和Java栈,PC寄存器的值总是指向下一条方法的执行指令,Java栈则存储Java方法调用的状态,包括局部变量,参数,返回值以及中间结果等
本地方法栈中存储本地方法的状态
class Lava{ private int speed = 5; void flow(){ } } class Volcano{ public static void mian(String[] args){ Lava lava = new Lava(); lava.flow(); } }
虚拟机找到并读入Volcano.class文件,导入class文件中的二进制数据流提取类型信息到方法区
执行main()
检查Lava类是否已经被装载
查找装载Lava.class
虚拟机以一个直接指向方法区Lava类数据指针来替换常量池第一项
虚拟机分配足够内存,初始化为0
堆
和方法区一样,可以是不连续的内存
两种实现方式
Java栈
Java栈的两种操作:以帧为单位的压栈和入栈
某线程正在执行的方法称为当前方法,当前方法使用的栈帧为当前帧,当前方法所属类为当前类,当前类的常量池为当前常量池
当线程执行一个方法时,虚拟机会在该线程的Java栈中压入一个新帧,在执行这个方法时,它使用这个帧来存储参数,局部变量,中间运算结果等
栈帧由局部变量去,操作数栈和帧数据区
addAndPrint将int 1和double 88.88压入到它的操作数栈中,调用addTwoType,解析此方法,分配内存压入栈帧,从addAndPrint操作数栈弹出int和double放在addTwoType的局部变量区,
addTwoType返回时,将返回值double 89.88压入操作数栈,虚拟机使用帧数据区的信息找到调用者addAndPrint,将返回值压入addAndPrint的操作数栈并释放addTwoType的栈帧内存,执行下一条指令
帧数据区的任务主要有:
a.记录指向类的常量池的指针,以便于解析。
b.帮助方法的正常返回,包括恢复调用该方法的栈帧,设置PC寄存器指向调用方法对应的下一条指令,把返回值压入调用栈帧的操作数栈中。
c.记录异常表,发生异常时将控制权交由对应异常的catch子句,如果没有找到对应的catch子句,会恢复调用方法的栈帧并重新抛出异常。