Jvm回顾

作者: 木子苇苇 | 来源:发表于2020-05-08 10:26 被阅读0次

    1.Jvm是什么

    全称是Java Virtual Machine, 是运行在物理计算机上的运行Java代码的虚拟计算机;

    它主要由两个子系统, 两个组件组成;

    1.png

    1.1 两个子系统

    • 类加载子系统(class loader): 将java全限定名称的class文件加载到Jvm
    • 执行引擎(execution engine): 执行class中的java指令, 收集jvm运行时垃圾对象
    类加载器

    java文件被编译后生成的class文件中会包含两个方法<cinit>, <init>

    <cinit>是jvm加载class生成Class对象调用方法

    <init>是创建对象时调用的方法

    加载class文件
    对class文件做连接
    初始化class: 对该类的静态变量赋正确的初始值
    使用class
    卸载class
    

    第2个做连接的阶段可以分为3个步骤

    1. 检查阶段: 主要做java魔术, 版本, 语义, 符号量等的检查
    2. 准备阶段: 为类中静态变量分配内存空间, 并赋默认值
    3. 解析阶段: 字符引用解析为直接引用

    类卸载阶段

    1. 该类的所有对象全部被回收
    2. 该类的classloader被回收
    3. 该类的class对象没有被引用
    class被加载的时机
    1. new一个class的对象
    2. 调用类的静态变量和静态方法
    3. 反射一个类
    4. 主动加载一个类class.forName("xxx.class")
    5. 初始化一个子类
    6. main启动类函数

    1.2 两个组件

    • Jvm运行时数据区(runtime data area): jvm内存
    • 本地方法接口(native interface): 调用本地方法的交互接口
    jvm运行时数据内存
    QQ截图20200509173935.png

    根据《Java 虚拟机规范(Java SE 7 版)》规定, Java 虚拟机所管理的内存如上图所示

    分为方法区, 堆, 虚拟机栈, 程序计算器, 本地方法栈

    方法区: 存储类加载后生成的类信息, 运行时常量池和及时编译后的代码
    虚拟机栈: 存储线程运行时的方法数据, jvm为每个运行的线程分配一个栈内存, 线程中每执行一个方法会向栈中压入一个栈帧, 栈帧信息包括局部变量, 操作数栈, 动态连接和方法返回
    本地方法栈: 存储jvm调用本地方法运行时数据
    堆: 存储java运行时生成的对象
    程序计算器: 存储线程当前运行到位置信息, 为每个线程分配一个计算器
    
    常量池

    /* java中的常量池可以分为静态常量池, 运行时常量池和String常量池 */

    静态常量池: java编译成class文件后class中的一段数据代码, 该区域主要存储字面量和符号引用

    运行时常量池: class被加载到jvm后, 存储静态常量池的内存

    String常量池: String在java中被定为为final的, 为了加速String的数据访问, jvm在方法区开辟出一块内存区域用户存放运行时产生的String数据, 类似缓存的概念; 池中的String对象会被一个表维护着引用, 保持在GC时不会被回收

    基本数据类型的缓存池: ByteCache, CharacterCache, ShortCache, IntegerCache, LongCache缓存1KB([-128, 127])的数据

    方法区

    方法区是虚拟机规范中的一块内存区域, 该区域主要是存放jvm加载的类的信息, 每个jvm对方法区的实现都有差异

    方法区存放类的数据结构, String常量池和运行时编译后的代码, 类的数据结构主要为类全限定名, 符号量和字面量的常量池, 静态变量, 方法描述

    // java8将永久代改为元空间主要做以下的考虑
    String常量池可能引起OOM
    永久代的GC效率低, 浪费较多时间
    永久代内存需在jvm启动之前定义, 不能随着物理服务的内存做动态调整
    
    // java8之后的方法区的调整
    类元信息被存放到了metaspapce
    常量池和静态变量被存放到了heap中(常量池和静态变量都是对象需要被GC)
    
    方法区 详细信息 源码中的示例
    类的信息 类的全限定名, 父类的全限定名, 类的类型标识(接口, 类, 注解), 类的访问限制描述(public, protect, private, default) abstract class com.inus.Test extends com.inus.TestSuper
    minor version: 0
    major version: 52
    flags: ACC_SUPER, ACC_ABSTRACT
    常量池 类的所有常量的有序集合, 符号量(类型, 字段, 方法的描述符)和字面量(基本数据类型和String的常量), 栈帧中的动态链接主要就是对这部分内存的引用 Constant pool:
    #1 = Class #2 // com/inus/Test
    #2 = Utf8 com/inus/Test
    #3 = Class #4 // com/inus/TestSuper
    #4 = Utf8 com/inus/TestSuper
    字段信息 字段全限定名, 字段类型, 访问修饰符 public static final com.inus.TestSuper CONST;
    descriptor: Lcom/inus/TestSuper;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    方法信息 包括够着方法, 静态块和类中定义的方法方法<br />全限定名, 方法修饰符, 方法参数, 方法执行指令 public com.inus.Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
    stack=1, locals=1, args_size=1
    0: aload_0
    1: invokespecial #18 // Method com/inus/TestSuper."<init>":()V
    4: return
    LineNumberTable:
    line 21: 0
    line 24: 4
    LocalVariableTable:
    Start Length Slot Name Signature
    0 5 0 this Lcom/inus/Test;
    类加载器的引用 当类加载后, 方法区中会保留一份对该类加载器的引用
    Class对象的引用 类加载完成后jvm会创建一个Class的对象, 方法区会保留一份对该类对象的引用 this.getClass().getName() 就是通过这个引用获取Class的信息的

    // 方法区的实现: metaspace

    jdk8为每个classloader分配一个本地内存区域, 这些内存区域合起来就是metaspace

    确保类和类元数据和加载该类的classloader的生命周期是保持一致的

    2.Jvm GC

    Jvm的基本算法

    1. 标记-清除: 先标记heap中无用类, 然后执行回收操作, heap内存中会出现大量内存碎片
    2. 复制: 开辟两块内存区域, 每次使用一块, 来回复制存活的对象, 存在内存浪费(新生代算法)
    3. 标记-整理: 先标记heap无用对象, 然后将存活对象向内存一端整理, 该算法存在对象移动(老年代算法)
    4. 分代收集: 将heap内存分为几个特征比较明显的区域, 对不同特征区域的heap进行不同的回收算法
    3.png

    年轻代收集器

    1. Serial: 串行化垃圾回收器, 复制算法
    2. ParNew: Serial的多线程版本, 也是复制算法
    3. Parallel Scavenge: 优化后的ParNew收集器, 优先吞吐量

    老年代垃圾收集器

    1. Serial Old: Serial的老年代版本, 标记整理算法
    2. Parallel Old: Parallel Scavenge的老年代算法, 也是标记整理算法
    3. CMS(Concurrent Mark Sweep): 并行标记整理算法

    G1垃圾回收器

    标记整理算法, 针对jvm整个堆做GC;

    将heap划分为n个指定的大小的region, eden年轻代, Survivor区和老年代各占n个region

    相关文章

      网友评论

          本文标题:Jvm回顾

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