第二章 JVM规范

JVM概述

  • 虚拟机指的是:通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的计算机系统
  • JVM是通过软件来模拟Java字节码的指令集,是Java程序的运行环境

    JVM规范

  • JVM规范为不同硬件平台提供了一种编译Java技术代码的规范

  • 该规范使Java软件独立于平台,因为编译时针对作为虚拟机的“一般机器”而做
  • 这个“一般机器”可用软件模拟并运行于各种现存的计算机系统,也可用硬件来实现

    JVM规范定义的主要内容
  • 字节码指令集(相当于CPU)

  • Class文件的格式
  • 数据类型和值
  • 运行时的数据区
  • 栈帧
  • 特殊方法
  • 类库(eg.对硬件)
  • 异常
  • 虚拟机的启动加载、链接和初始化

    JVM规范中的虚拟机结构

    如何学习JVM规范中的指令集

    可看《jvm规范》

    理解ClassFile结构
  • Class文件时JVM的输入,Java虚拟机规范中定义了Class文件的结构。Class文件是JVM实现平台无关、技术无关的基础

  1. Class文件是一组以8字节为单位的字节流,各个数据项目按顺序紧凑排列。
  2. 对于占用空间大于8字节的数据项,按照高位在前的方式分割成多个8字节进行存储
  3. 只有两种类型:无符号数、表
    1. 无符号数 u1
    2. 表 由无符号数和表复合数据类型 “_info”
  4. javap工具生成非正式的“虚拟机汇编语言”,格式如下[<>][]
    1. 是指令操作码在数组中的下标,该数组以字节形式来存储当前方法的Java虚拟机代码,也可以相对于方法起始处的字节偏移量
    2. 是指令的助记码,还有操作数和注释
      常量池
      类定义和属性
      方法和方法调用
  • stack:方法执行时,操作栈的深度
  • Locals:局部变量所需的存储空间,单位是slot
  • args_size: 参数个数

    总结

    根据classFile结构规范,去读每一小段,然后根据每一段的结构和索引去读出具体的内容。
    可以看到虚拟机如何执行程序的,
    虚拟机如何执行优化的。
    可以直接操作字节码

    ASM

  • ASM是一个Java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。

  • ASM可以直接产生二进制Class文件,也可以在类被加载入虚拟机之前动态改变类行为,ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能根据要求生成新类。
  • 目前许多框架如cglib、Hibernate、Spring都直接或间接地用ASM操作字节码

    ASM编程模型
  • Core API

操纵字节码的功能基于ClassVisitor接口,三个,实现class生成和转换

  1. ClassReader解析一个类的class字节码
  2. ClassAdapter是ClassVIsitor实现类,实现要变换的功能
  3. ClassWriter 输出字节码
  • Tree API

    第三章 类生命周期

    类的生命周期

  • 加载:查找并加载类文件的二进制数据

  • 连接:将数据合并到JVM运行时环境中取,包括如下几个步骤:
  1. 验证:确保被加载类的正确性
  2. 准备:分配内存
  3. 解析
  • 初始化

    类加载

    9bb488d4-6366-4cd9-be06-1bc4e2e62ab5.png
    启动类

    双亲委派模型

    破坏双亲委派模型

    类连接

    验证
  • 类文件结构检查

  • 元数据验证
  • 字节码验证

    准备

    解析

    符号引用-直接引用

    类的初始化

    就是为类的静态变量赋初始值,或者说是执行类构造器方法的过程
    1)如果类还没有加载和连接,就先加载和连接
    2) 没有初始化父类,就先初始化父类
    3) 类中存在类中初始化语句(static块)
    4)接口的话,初始化一个类的时候,不会初始化他的接口,初始化接口的时候,不会初始化他的父接口。只有调用接口里的变量时,才会初始化接口。classLoader装载一个类,并不会初始化这个类,不是对类的主动使用。
    类的使用方式

  • 主动使用 初始化时机
    1)创建类实例
    2)访问某个类或接口的静态变量

  1. 静态方法
    4)反射某个类
    5)初始化某个类的子类
    6)JVM启动的时候运行的主类
    7)定义了default方法的接口,当接口实现类初始化时
  • 被动使用

被动引用:通过子类去引用父类的静态字段
数组引用这个类
访问常量final不会初始化,本质上是从去常量池里拿的
69cba930-2988-48b3-8342-280697fd8708.png

类卸载
  • 当Class对象不再被应用,那么Class对象的生命周期就结束了,对应的在方法区中的数据也会被卸载
  • JVM自带类加载器装载的类,是不会卸载的,有用户自定义的类加载器是可以卸载的
  • b569ea97-0204-42f4-b1d0-624a2277b6bc.png

    第四章 内存分配基础

    java的简化架构

    运行时数据区

  • PC寄存器

    • 每个线程拥有一个PC寄存器,是线程私有的,用来存储指向下一个指令的地址
    • 在创建线程的时候,创建相应的PC寄存器
    • 执行本地方法时,PC寄存器的值为undefined
    • 是一个比较小的内存空间,是唯一一个在JVM规范中没有规定OutOfMemoryError的内存区域
  • java栈
    • 栈由一系列帧组成(因此java栈也叫java栈帧),是线程私有的
    • 帧用来保存一个方法的局部变量操作数栈(Java没有寄存器,所有参数传递都是用操作数栈)、常量池指针、动态链接、方法返回值等
    • 每一次方法调用创建一个帧,并压栈,退出方法时候,修改栈顶指针就可以把栈帧中的内容销毁
    • 局部表量表存放了编译期可知的各种基本数据类型和引用类型,每个slot存放32位数据
    • 栈优点:存取数据比堆快,仅次于寄存器
    • 站缺点:数据大小、生存期在编译期决定的,缺乏灵活性

  • java堆
    • 用来存放应用系统创建的对象和数组,所以线程共享Java堆
    • GC主要管理堆空间,对分代GC来说,堆也是分代的
    • 优点:运行期动态分配内存大小,自动进行垃圾回收
    • 缺点:效率相对较慢
  • 方法区
    • 线程共享,通常用来保存类的结构信息(常量池、方法字节码)
    • 通常和元空间关联在一起,但具体的跟JVM实现和版本有关
    • JVM规范把方法区描述为堆的一个逻辑部分,但他有一个别称Non-heap,与Java堆区分开
  • 运行时常量池
    • 是Class中每个类和接口的常量池表,在运行期间的表现形式,通常包括: 类的版本、字段、方法、接口等信息
    • 在方法区中分配
    • 通常在加载到JVM之后就创建
  • 本地方法栈
    • 在jvm中支持native方法执行的栈就是本地方法栈
  • 栈、堆、方法区交互关系
    36f5f218-9950-40f3-aee8-acf368e793e3.png

    Java堆内存

    概述

    逻辑上连续,

  • Java堆式在运行期动态分配内存大小,自动进行垃圾回收

  • GC主要就是回收堆内存,对分代GC来说,堆也是分代的

    Java堆的结构

    65f97272-2aeb-458b-8b47-b6a552e046f4.png

  • 新生代:存放新分配的对象

  • 年龄
  • 老年代 比较大的对象
  • 整个堆=
  • 新生代=Eden+存货去
  • 持久代 存Class、Method等原信息 从JDK8开始去掉了,取而代之的是元空间,元空间并不在虚拟机里面,而直接使用本地内存

    对象的内存布局

    2e25628b-cc0a-464f-b55d-0234bf5839e5.png
    2f477f3c-3b6a-4764-8e2d-5441303aada3.png

  • 对象的访问定位

  • 访问方式取决于JVM的实现,句柄/类型指针
    6b1bde82-f5f3-428e-b4d0-3ec2feacd73e.png
    间接引用,慢一点
    6c4d24af-c78d-445b-846d-0aa55b04b0f6.png
    hotpot,速度快

    Java内存分配参数

    Trace跟踪参数

    -Xlog:GC

    GC日志格式
  • GC发生时间,也就是JVM从启动以来经过的秒数

  • 日志级别信息,和日志类型标记
  • GC识别号
  • GC类型和说明GC原因
  • GC前后容量
  • GC持续时间,单位秒

    Java堆的参数

    最小初始化堆,默认物理内存1/64

  • Xms: 1024倍数且大于1m

  • -XX:inHeapSize
    Runtime.getRuntime().totalMemory().
    初试最大堆, 最小初始化堆1/4,
  • -Xmx:
  • -XX:MaxHeapSize

建议初始堆和最大堆配置一样,减少内存分配的开销

使用MAT进行内存分析

把当前内存dump出来,
b60b3a17-7873-44f8-ae51-3ffa402e8750.png
原因:

  1. 内存泄漏,只往上涨,不往下降低(不恰当的引用)
    7a85ac9d-daf5-491e-93b2-0f3c1d190442.png
  • 老年代/新生代

缺省为2
c34a4ac8-4153-4993-899b-3ccb41720a0e.png

  • -Xss: 每个线程的堆栈大小,通常几百k,决定了函数调用的额深度

递归
https://blog.csdn.net/qq_31331965/article/details/102465589

  • 元空间的参数

67fa578f-c2c5-4d59-96f0-6d18994a9b98.png

第五章 字节码引擎

字节码引擎

字节码引擎概述

  • 功能基本就是 输入字节码文件,然后对字节码进行解析并处理,最后输出执行的结果
  • 实现方式可能有通过解释器直接解释执行字节码,或者是通过及时编译器产生本地代码,也就是编译执行,当然也可能两者皆有。

    栈帧概述

  • 栈帧用于支持JVM进行方法调用和方法执行的数据结构

  • 栈帧随着方法调用而创建,随着方法结束而销毁
  • 栈帧里存储了方法的局部变量、操作数栈、动态链接、方法返回地址等信息
    2896f8f1-1880-430d-a247-44594f15b5d3.png

    局部变量表

  • 局部变量表:用于存放方法参数和方法内部定义的局部变量的存储空间
    a143c7c0-2d97-4ec3-b8fe-8440f2230a05.png

  • image.png

    案例1 slot是可复用的

  • image.pngimage.png

  • 不用的变量显式地置为null

    案例2 操作数栈

    image.png

    动态连接

    image.png

    方法返回地址

    方法执行后返回的地址

    方法调用

    image.png

    分派

    image.png

第六章 垃圾回收算法

1、什么是垃圾
简单说就是内存中已经不再被使用到的内存空间就是垃圾
2、如何判定垃圾
image.pngimage.png
image.pngimage.png

3、如何回收
各种引用的实现

  • 软引用
  • 弱引用
  • 需应用

image.pngimage.png
image.pngimage.png
image.pngimage.png

4、根搜索算法、引用分类、GC类型、垃圾收集类型

image.png
image.png
image.pngimage.png
image.png
image.png

垃圾收集算法

image.pngimage.png

image.pngimage.png
image.pngimage.png
image.png
image.png
image.png
image.png
image.png
image.png

垃圾收集器

image.png
image.png
image.png

image.pngimage.png

image.png
image.pngimage.png
image.pngimage.png
image.pngimage.png
image.png
image.png
image.pngimage.png
image.png

image.pngimage.png
image.png
image.png
image.pngimage.png
image.png
image.pngimage.png
image.png
image.png
image.pngimage.png
image.pngimage.png
跟踪和记录分析,
image.png
image.png

触发fullgc的条件、对象分配规则

https://blog.csdn.net/z69183787/article/details/52757727
image.png

垃圾回收视频课

https://www.bilibili.com/video/BV1D741177rV?from=search&seid=17138143945258049311

三色标记 和 读写屏障

https://www.jianshu.com/p/12544c0ad5c1

JVM对高效并发的支持

image.png
image.pngimage.png
image.png
image.pngimage.png
image.pngimage.png
image.pngimage.png
image.png
image.png
image.pngimage.png