虚拟机字节码执行引擎
运行时栈帧结构
• 局部变量表 • 操作数栈 • 动态链接 • 方法返回地址 • 附加信息
局部变量表
• slot 32 64 • 数据类型:byte boolean short char int float double long reference(ccs) returnAddress • slot 复用:当一个变量的pc寄存器的值大于Slot的作用域的时候,Slot可以复用
代码语言:javascript复制/**
* 局部变量表 复用slot
* -verbose:gc
*/
public class GCDemo {
public static void main(String[] args) {
{
byte[] buff = new byte[1024 * 1024 * 30];
}
int a = 0;
System.gc();
}
}
操作数栈
操作数栈(Operand Stack)也常被称为操作栈,它是一个后入先出(Last In First Out,LIFO)栈
动态连接
Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就被转化为直接引用,这种转化被称为静态解析。另外一部分将在每一次运行期间都转化为直接引用,这部分就称为动态连接。
代码语言:javascript复制package jvm;
/**
* 动态链接
*/
public class Demo3 {
static class Super{
public void test() {
System.out.println("parent");
}
}
static class Sub1 extends Super {
public void test() {
System.out.println("Sub1");
}
}
static class Sub2 extends Super {
public void test() {
System.out.println("Sub2");
}
}
public static void main(String[] args) {
Super c1 = new Sub1();
Super c2 = new Sub2();
c1.test();
c2.test();
}
}
运行结果:
代码语言:javascript复制Sub1
Sub2
方法返回地址
方法调用时通过一个指向方法的指针,方法返回时将回归到调用处,那个地址就是返回地址
方法调用
解析
调用目标在程序代码写好、编译器进行编译那一刻就已经确定下来。这类方法的调用被称为解析(Resolution) • 静态方法、构造器、私有方法,final修饰的方法
分派调用
静态分派
代码语言:javascript复制package jvm;
/**
* 静态分派示例
*/
public class Demo02 {
static class Super{
}
static class Sub1 extends Super {
}
static class Sub2 extends Super {
}
public void test(Sub1 sub1) {
System.out.println("sub1 is called");
}
public void test(Sub2 sub2) {
System.out.println("sub2 is called");
}
public void test(Super parent) {
System.out.println("parent is called");
}
public static void main(String[] args) {
Super c1 = new Sub1();
Super c2 = new Sub2();
Demo02 demo02 = new Demo02();
demo02.test((Sub1) c1);
demo02.test(c2);
}
// Code:
// stack=2, locals=4, args_size=1
// 0: new #7 // class jvm/Demo02$Sub1
// 3: dup
// 4: invokespecial #8 // Method jvm/Demo02$Sub1."<init>":()V
// 7: astore_1
// 8: new #9 // class jvm/Demo02$Sub2
// 11: dup
// 12: invokespecial #10 // Method jvm/Demo02$Sub2."<init>":()V
// 15: astore_2
// 16: new #11 // class jvm/Demo02
// 19: dup
// 20: invokespecial #12 // Method "<init>":()V
// 23: astore_3
// 24: aload_3
// 25: aload_1
// 26: checkcast #7 // class jvm/Demo02$Sub1
// 29: invokevirtual #13 // Method test:(Ljvm/Demo02$Sub1;)V
// 32: aload_3
// 33: aload_2
// 34: invokevirtual #14 // Method test:(Ljvm/Demo02$Super;)V
// 37: return
// LineNumberTable:
// line 27: 0
// line 28: 8
// line 29: 16
// line 30: 24
// line 31: 32
// line 32: 37
// LocalVariableTable:
// Start Length Slot Name Signature
// 0 38 0 args [Ljava/lang/String;
// 8 30 1 c1 Ljvm/Demo02$Super;
// 16 22 2 c2 Ljvm/Demo02$Super;
// 24 14 3 demo02 Ljvm/Demo02;
}
运行结果:
代码语言:javascript复制sub1 is called
parent is called
invokevirtual 静态分派好了
动态分派
重要体现:重写
代码语言:javascript复制package jvm;
/**
* 动态链接
*/
public class Demo3 {
static class Super{
public void test() {
System.out.println("parent");
}
}
static class Sub1 extends Super {
public void test() {
System.out.println("Sub1");
}
}
static class Sub2 extends Super {
public void test() {
System.out.println("Sub2");
}
}
public static void main(String[] args) {
Super c1 = new Sub1();
Super c2 = new Sub2();
c1.test();
c2.test();
}
}
运行结果:
代码语言:javascript复制Sub1
Sub2
在运行期根据实际类型确定方法执行版本的分派过程称为动态分派。
动态语言支持
何谓动态类型语言 ?动态类型语言的关键特征是它的类型检查的主体过程是在运行期而不是编译期进行的,满足这个特征的语言有很多,常用的包括:APL、Clojure、Erlang、Groovy、JavaScript、Lisp、Lua、PHP、Prolog、Python、Ruby、Smalltalk、Tcl,等等。那相对地,在编译期就进行类型检查过程的语言,譬如C 和Java等就是最常用的静态类型语言。
代码语言:javascript复制package jvm;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
* 动态语言
*/
public class DynamicLanguage {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine javaScript = scriptEngineManager.getEngineByName("JavaScript");
Object eval = javaScript.eval("function add(a,b) {return a b;} add(2,3);");
System.out.println(eval);
}
}