JVM

#类加载器

###ClassLoader(类加载器)

  • 加载:查找并加载类的二进制数据
  • 连接:
    • 验证:确保被加载的类的正确性
    • 准备:为类的静态变量分配内存,并将其初始化问默认值
    • 解析:把勒种的符号引用转换为直接引用
  • 初始化:为类的静态变量赋予正确的初始值

###主动使用-类-初始化

  • 创建类的实例
  • 访问某个类或者访问类的静态变量,或者对静态变量赋值
  • 调用类的静态方法
  • 反射 (Class.forName)
  • 初始化一个类的子类
  • Java虚拟机启动是包含main函数的类

###类的加载

将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个Java.lang.Class对象,用来封装类在方法区内的构造函数。

#对象的内存布局

###对象

对象在内存中的存储布局分为3块区域:对象头,实例数据,对齐填充

对象头包括 Mark Word 如哈希码,GC分代年龄,锁状态标志,线程持有锁,偏向锁id,偏向时间戳。

对象头还包括类型指针,指向方法区中的那个类实例

###对象的访问定位

reference类型来操作具体对象

  • 句柄引用,句柄中包含了实例数据和类型数据的地址信息(方法区)
  • 直接引用,存储的就是对象的地址,对象中还包含有类型数据的地址信息(方法去)

#枚举根节点

###stop the world

  • OopMap 记录哪些地方是存储着对象引用

  • 安全点(safe point) 在安全点上时,线程可以进入GC

安全点选在以程序“是否具有让程序长时间执行的特征(指令序列复用,比如方法调用,循环指令,异常跳转)”

当需要GC时,设置一个标志,各个线程执行时都会去轮询这个标志,然后在安全点自己主动挂起

  • 安全区域(safe Region) 指在一段代码片段中,引用关系不会发生变化,在任意地方GC都是安全的,当线程执行到安全区域,首先把自己表示为进入安全区域,当离开时,需要检查系统是否完成了根节点枚举。

#方法区中的永久区资源清理

  • 常量 当没有对象引用这个常量时,如果内存不足的话,才会被清理

  • 类 判断类的条件比较苛刻

    • 该类的所有实例都被回收
    • 加载该类的ClassLoader已经被回收
    • 该类的java.lang.Class对象没有在任何地方被引用,没有被反射调用该方法

#Class文件

###包括无符号数和表

无符号数包括u1,u2,u4,u8(1字节,2字节,4字节,8字节)

表可以包含多个表,以_info结尾

###Class文件

魔数 0xCAFEBABE

主次版本号第5,6为次版本号,7,8为主板本号

常量池

访问标记

类索引和父类索引 接口索引集合

……

#类的加载

加载-(验证-准备-解析)【连接】-初始化-使用-卸载

###开始加载

  • 遇到new,读取或者设置一个类的静态字段,以及调用一个类的静态方法时
  • 使用java.lang.reflect包的方法对类进行反射调用
  • 当初始化一个类是,如果父类没有初始化,则初始化父类
  • 当虚拟机启动时,初始化包含main函数的类

###加载的工作

  • 通过一个类的全限定名来获取定义此类的二进制字节流。
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 在内存中(堆)生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

###验证

  • 文件格式验证

验证字节流是否符合Class文件的规范,并且可以由当前版本的虚拟机进行处理

  • 元数据验证(数据类型的验证,类是否合法)

对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言的规范要求

  • 字节码验证

通过数据流和控制流分析,确定程序语义是否合法,符合逻辑,对类的方法体进行校验分析

  • 符号引用验证

对类自身以外的信息进行匹配性校验

###准备

准备节点是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。内存分配的仅包括类静态变量(static),初始值是该数据类型的零值,不是代码设置的值。

###解析

解析阶段虚拟机将常量池内的符号引用替换为直接引用的过程

###初始化

根据程序员通过程序制定的主管计划去初始化类变量和其他资源