美文网首页
深入JAVA虚拟机-第二版

深入JAVA虚拟机-第二版

作者: Kingty | 来源:发表于2017-03-13 19:42 被阅读0次

    第一章 JAVA体系结构介绍

    • java应用程序可以使用两种类装载器,启动(bootstrap)类装载器和用户自定义装载器。
      每一个类被装载的时候,java虚拟机都监视着这个类,看它是被什么装载器装载的,当被装载的类引用了其他类的时候,
      会使用相同的类装载器去装载被引用的类。因此默认情况下只能看到被同一个类装载器装载的类,通过这种方法,java允许
      在java程序中简历多个命名空间,每一个类加载器都有自己的命名空间。
    • class 文件,运行在JVM上的二进制文件

    第三章 安全(--看完再回顾本章)

    • JAVA沙箱中类装载体系结构是第一道防线
    • 防止恶意代码干涉善意代码
    • 守护被信任类库的边界
    • 将代码分类,确定该类代码可以执行些些操作
    • class 文件检测器
    • 检验字节码的的完整性
    • 类型数据语义检查
    • 字节码验证
    • 符号引用验证
    • 二进制兼容
    • JVM内置安全特性
    • 类型安全的引用转换
    • 结构化的内存访问
    • 自动垃圾收集
    • 数组边界检查
    • 空引用检查
    • 禁止对内存进行非结构化访问
    • 异常的结构化处理
    • 安全管理器和java api
    • 代码签名和认证,将一个未签名的class文件通过散列和私钥得到一个带有签名后散列的文件
    • 访问控制器

    第五章 java虚拟机

    • 生命周期,main作为函数的起点,每一个程序都运行一个虚拟机实例上。java虚拟机上两种线程,一种是守护线程,另一种是非守护线程
      守护线程是由jvm自己使用的,比如垃圾回收的线程,而开始于main函数的线程是非守护线程。只要还有非守护线程在运行,虚拟机还是存活的
      ,所有非守护线程退出时,虚拟机会自动退出。

    java 虚拟机的结构体系

                                 -------------------
                                |   类装载器子系统    |           
                                 -------------------
                                         |
        ------------------------------------------------------------------
        |    |        |         |              |                   |      |
        |  方法区      堆       java栈        PC寄存器            本地方法栈  |
        ------------------------------------------------------------------
              |                             |
           执行引擎    ————————————————>  本地方法接口
    
    
    • 一些点
    • 方法区和堆内存是由所有的线程共享的,虚拟机装载class文件时,会把类的数据放在方法区中,当程序运行时,会把根据类数据创建的对象
      放在堆内存中。
    • 当新线程被创建时,都将得到一个PC寄存器和一个JAVA栈PC寄存器总是指向下一条被执行的指令,java栈则存储方法的调用状态。(局部变量,参数返回值,运算中间值)
    • java 栈是有很多的栈帧组成,当线程调用一个方法的时候,,JVM将新的栈帧入栈,当函数返回时,栈帧被出栈。
    • 数据类型
    • 基本类型(float, double, byte, short, int, long, char, boolean, returnAddress)
      64 32 8 16 32 64 16
    • 引用类型(类,接口 ,数组)

    方法区

    • 方法区的数据共享,因此是必须线程安全的。虚拟机允许程序员指定方法区的大小
    • 方法区会在内存中存储类的以下信息:
    • 类型的全限定名(包名+.+类名)

    • 此类超类的全限定名

    • 类还是接口

    • 修饰符(public ,abstruct, final)

    • 接口全限定名的有序列表

    • 类型的常量池

    • 字段信息(字段名,类型,修饰符)

    • 方法信息(方法名,类型,修饰符)

    • 一个到类ClassLoder的引用

    • 一个到Class类的引用(forName(),让用户得到已装载对象的Class实例)

    • 方法字节码

    • 操作数栈和该方法在栈帧中局部变量的大小

    • 异常表

    • 下面看一看流程

    class Volcano(){
        public static void main(String args[]){
            Lava lava = new Lava();
            lava.flow();
        }
    }
    
    • 例如我们要执行一个叫Volcano的类,当我们告诉JVMVolcano这个名字
    • JVM会找到并读入Volcano.class文件
    • 然后导入其中的二进制流,并把相应的数据存在方法区
    • 通过执行方法区中的字节码,开始执行main()方法,在执行时会一直持有指向常量池的指针
    • main方法中第一条指令是给常量池第一个类分配象的内存,于是在常量池中找到第一项,发现是对另一个类Lava的引用
    • 检查方法区,看是否被装载,发现没有被装载,于是查找Lava.class文件装载,同样把信息存储在方法区中
    • 接着指向常量池第一行的指针替换掉常量池的第一项(Lava的全限定名)-> 常量池的解析(符号引用替换成直接引用,本地指针)
    • 虚拟机准备为Lava分配内存,并用这个指针访问它的类信息,找出类信息中的需要为这个类分配多少堆内存
    • 虚拟机确定了大小,就在堆上为对象分配内存,并初始化常量值。然后把对象的引用入栈,第一条指令执行完成。
    • 接下来通过这个引用调用flow方法

    两种堆设计
    • java一个虚拟实例中只有一个堆空间,所有线程共享

    • java 只有在堆中分配内存的指令,没有释放的指令,垃圾收集器会负责堆和方法区的内存回收

    • 堆和方法区一样也不是一个连续的内存区,是可扩展的

    • 堆上的对象还有一部分数据,是对象锁(互斥锁),请求可以追加,请求几次,必须释放几次,例如请求了4次,只释放了3次,那还是持有这个对象锁。

    • 堆上对象还有一部分数据与垃圾收集器有关,垃圾回收器必须跟踪每个对象。

    • 数组是一个对象,总是存储在堆中

    • PC(程序计数器)寄存器,在每个线程中有一个,它有一个字的大小,存储一个本地指针,总是指向下一条将要执行的指令。

    java 栈

    过程
    • 每当启用一个线程,JVM会为它分配一个java 栈。
    • 栈帧的组成
    • 局部变量区 -> 一个数组,以字(32bit)为单位,类型int,float,returnAddress的值再数组中占一项,byte,short,char会被转化成int,也占一项,double,long占2项。任何一个实例方法(非static),的数组第一项都是对象本身的reference.
    • 操作数栈 -> byte,short,char会被转化成int,和上面一样,只有在存回堆中是会被转化为原来类型。他也是一个数组,但是按照栈操作来访问。由于java虚拟机没有寄存器,java的指令是通过操作数栈中取得操作数的。
    • 栈帧数据,支持常量池的解析正常方法返回和异常派发机制的数据。
      为了处理执行期的异常退出情况,帧数据区保存一个对此方法的异常表的引用。当方法抛出异常,会在异常表中查找对应的异常,如果找到了匹配的catch语句,就会交给ccatch中的代码处理,如果没有则异常中止。
    • 两站不同的虚拟机实现的帧分配


    • 本地方法栈,取决于设计者的实现

    执行引擎(没看太明白)

    • 运行中java程序的每一个线程都是一个独立的虚拟机执行引擎的实例。
    • 从线程的生命周期开始,它要么在执行字节码,要么在执行native方法。
    • 指令集,指令集关注的中心是操作数栈。操作数栈中的数值必须按照适合他们类型的方式使用。比如压入栈4个int,却把他们当做两个long来做操作,是非法的 。

    第六章 JAVA class文件 (粗略看)

    • java class文件是对java程序二进制文件的精确定义。一个class文件中指包括一个class 或者interface.

    • class文件不一定与java语言有关,别的语言也可以编译成class文件在虚拟机上运行。

    • class 文件组成
    • magic ,每个class文件的前四个字节 0xCAFEBABE,用来分辨是否是class文件。
    • minor_version major_version b版本号。
    • constant_pool_count 常量池的数量,constant_pool 常量池
    • access_flags 类的修饰信息,public ,private ,static 等
    • this_class 指向常量池的索引
    • super_class 超类常量池索引

    第七章 类型的生命周期

    • 类主动装载的时机
    • 创建实例时(new, 反射,克隆,反序列化)
    • 调用类中的静态方法
    • 使用类或接口的静态字段或者对字段赋值(final 修饰的静态变量除外,它被初始化为一个编译时的常量表达式)
    • 调用api反射方法
    • 初始化子类
    • 含有main函数的类
    • 所有类的初始化都要求它的超类在此之前初始化了。(接口不是)
    • 装载
    • 通过完全限定名产生一个二进制流
    • 解析二进制文件
    • 创建一个该类型Class实例
    • 初始化
    • 所有类变量初始化语句和类型的静态初始化器都被java编译器收集到一起放在一个特殊的方法<clinit>中,并非所有的类都有这个方法。
    • 如果多个线程需要初始化一个类,仅仅允许一个线程来执行初始化,其他线程需要等待。完成后需要通知其他等待线程。
    对象生命周期
    • 实例化
    • new

    • reflect.newInstance()

    • clone()

    • ObjectInputStream.getObject

    • 堆中分配内存,然后赋予实例变量初始值

    • 类型当没有引用的时候会被卸载,同样通过垃圾回收器。

    第八章 链接模型

    相关文章

      网友评论

          本文标题:深入JAVA虚拟机-第二版

          本文链接:https://www.haomeiwen.com/subject/hqbfnttx.html