从这张图我们可以清楚的看出来 我们写好的java代码是先经过编译生成class文件 然后才是我们jvm 要做的部分 意思就是java是面向编译之后的class文件产生的 用来屏蔽不同的操作系统在底层和硬件指令上的区别 把class文件翻译成为无论是什么机器都可以 "看懂"的机器码
课中主要讲解的就是jvm运行空间
栈实际上就是栈帧组成的, 而每一个栈帧又存储着与之对应的方法的局部变量表,操作数栈,动态链接,方法出口 也就是一个方法对应一个栈帧 栈帧就是java中每个方法的存放空间 局部变量表 : 存放着方法中的局部变量 操作数栈: 用来操作方法中的数的一个临时栈 动态链接:把符号引用存在直接应用存在内存空间中 方法出口: 记录该方法调用完毕应该回到的地方 (放到我们这个例子中就是回到Main函数的下一行)
下面是Math.java反编译的结果 具体分析compute()函数的指向流程 来深刻的理解帧栈这个空间
Compiled from "Math.java" public class com.shen.Main.jvm.Math { public static final int initDate; public com.shen.Main.jvm.User user; public com.shen.Main.jvm.Math(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: new #2 // class com/shen/Main/jvm/User 8: dup 9: invokespecial #3 // Method com/shen/Main/jvm/User."<init>":()V 12: putfield #4 // Field user:Lcom/shen/Main/jvm/User; 15: return public int compute(); Code: 0: iconst_1 1: istore_1 2: iconst_2 3: istore_2 4: iload_1 5: iload_2 6: iadd 7: iconst_3 8: imul 9: istore_3 10: iload_3 11: ireturn public static void main(java.lang.String[]); Code: 0: new #5 // class com/shen/Main/jvm/Math 3: dup 4: invokespecial #6 // Method "<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #7 // Method compute:()I 12: pop 13: return }栈帧的局部变量其实是用一个数组进行存储的 其中特殊的局部变量0就是this public int compute(); Code: 0: iconst_1 将局部变量1 放入到操作数栈 1: istore_1 将int类型的值存入局部变量1(将int值赋给在局部变量表的局部变量) 2: iconst_2 3: istore_2 (这就明白了 这两个实际上指行的就是 现在局部变量表中开辟一个b的空间 然后在从操作数栈中弹栈赋给局部变量b) 4: iload_1 //局部变量1压入栈 5: iload_2 //局部变量2 压入栈 6: iadd //弹栈两次 执行int 类型的add 7: iconst_3 //将计算结果 压入栈 8:bipush //将 10压入栈 9: imul //计算乘法结果 在压入栈中 10: istore_3 //将结果存给局部变量3 11: iload_3 //取出局部变量3的值 12: ireturn //return int
属于线程私有 用来存放线程执行代码的位置(就是.class文件中的行号) 由字节码执行引擎来操作
常量 (静态常量)
静态变量(指向堆空间)
方法信息
存放各种new出来的对象 局部变量表会指向 方法区 中的静态变量也会指向
//垃圾搜集都是字节码执行器在做
new 出来的对象都会往 Eden(伊甸)区放 然后满了 会进行minor gc存活的放到s0中再次满了 再次搜集s0和Eden存活对象 放到s1中…s1,eden–>s0 不断调换年龄到达15的 进入老年区老年区满了 会启动full gc 启动full gc时候必须暂停所有执行的代码也就是STW(stop the world) 因为我们的对象必须要有一个确定的状态 不暂停的话就无法确定