'深入理解Java虚拟机'读书总结2018-04-23

2018-04-23  本文已影响0人  lichao666

以下内容都是我自己对本书读后的一个理解,感觉总结一下理解的更深刻,如果能帮助到别人就更好了,可能会有些内容说的不正确,如果发现了,希望帮忙留言指正,谢谢。

背景

计算机的种类很多,硬件也都不太一样。比如Windows,Android,iOS等,而具体到某一个平台,也分32位,64位等。想要编写一个适用于众多平台的软件比较困难,要考虑到各个平台的兼容性。Java虚拟机就提供了这么一个平台,让开发者只关心程序的功能开发,兼容的工作就交给虚拟机即可。Java虚拟机做到了一次编译,到处运行。

在JVM上跑一个程序的大概过程

基于JVM的语言除了Java还有Groovy,JRuby,Scala,Fantom,Jython等。JVM支持的只有一种文件格式:.class文件。基于JVM的语言,不管语法是什么样的,脱去漂亮的衣服,最终都要编译成.class文件格式,才能在JVM虚拟机上运行。

.class文件结构

image.png

.class文件结构是固定这样的,ux就代表x个字节的内容,.class文件结构中只有两种数据内容:无符号数和表,表可以认为是一个数据结构,表中还是无符号数和表。

package com.ejushang.TestClass;
 public class TestClass implements Super{
     private static final int staticVar = 0;
     private int instanceVar=0;
     public int instanceMethod(int param){
         return param+1;
     }
 }
 interface Super{ }

该Java文件编译为class文件后:


class.png

我在"'深入理解Java虚拟机'2018-04-16"这个笔记中,手动将每一项内容都进行了分析,这里就直接用Javap -verbose TestClass输出常量表


cmd.png
ConstantPool就是常量池,索引对应的是常量池的第几个常量。

类加载

类从被加载到虚拟机内存中开始,到卸载出内存为止,生命周期包括:加载,验证,准备,解析,初始化,使用和卸载。


loa.png

什么情况下类被加载?由虚拟机来自由把握。

  1. 遇到new,getstatic,putstatic,invokestatic这4条字节码指令时
  2. 对一个类反射调用时
  3. 初始化一个类,如果父类还没初始化,则先初始化父类
  4. 用户指定一个要执行的主类(包含main()方法的那个类)
  5. 使用JDK1.7的动态语言支持时,如果java.lang.MethodHandler实例最后的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,需要先初始化

虚拟机字节码执行引擎

运行时栈帧结构,先了解下栈帧结构,为以后的运行代码过程做铺垫
虚拟机栈描述的是Java方法执行的内存模型。每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。


stack_frame.png

对象的创建,内存布局和访问

目前问题

Java程序从编译到运行完成的过程

public class A{
    int value;
    public String getValue(){
        return value;
    }
}

public class Example{
    public static void main(String args[]){
        A a = new A();
        a.getValue();
    }
}

1.Java代码编译为class文件,class中包含常量池,字段表,方法表,属性表等;
2.加载(虚拟机自己定义加载时机),将class文件加载到方法区,在堆中实例化一个Class对象,做为方法区中该类的入口;
验证;准备,为类变量分配内存,设置初值0;
解析,将常量池中符号引用替换为直接引用;
初始化,给类变量赋真正的初始值;
3.开始执行main方法,根据Example的全限定名在方法区中找到Example,找到name是main的方法,创建main方法栈帧,将参数args,对象引用a存储到main栈帧的局部变量表中,然后将new指令入栈(操作数栈),将参数A入栈,在堆中保存a对象实例。接下来方法调用指令入栈,参数入栈,参数中有a和getValue,可以根据这些内容找到方法区中A类getValue方法的地址,然后运行该方法,创建getValue方法栈帧,将return指令入栈(getValue的操作数栈),参数value入栈,该方法执行结束,value出栈,return指令出栈。根据程序计数器,跳回刚才的main栈帧的操作数栈中的位置。退出指令入栈,退出指令出栈,其他内容逐一出栈。OK,程序结束。

上一篇 下一篇

猜你喜欢

热点阅读