总结笔记(四) - JVM 总结

JVM 总结

什么是 JVM

JVM 是 Java 虚拟机,是一个虚拟出来的计算机,仿真模拟计算机。

JVM 在运行程序的时候,这个程序在 JVM 里面是怎么样的?

JVM 的内存主要分为五块

  1. 程序计算器

程序计算器是用来记录当前线程的执行的位置,通过程序计数器的记录,程序就可以继续进行下去。

线程私有的,就是每个线程都不一样。

需要注意的是这里面没有 OutOfMemory 的异常,在执行 native 方法的时候,记录是空值,一些循环,比如 forwhile 也是通过这个来实现的。

  1. 虚拟机栈

每一个线程都会有一个虚拟机栈,用于解释代码的执行过程。线程每调用一个方法的时候就会创建一个栈帧,并放到这个虚拟机栈中,方法执行完成后,这个栈帧出栈。

栈帧是什么呢?或者说里面是什么内容呢?栈帧主要包括以下 4 个内容:

  • 局部变量表(LocalVariableTable),里面是这个方法里面的用到的变量,this 是下标为 0 的变量
  • 操作数栈,JVM 是基于栈的,操作数可以理解为中间的计算结果,结果是保存在栈里面的。
  • 动态链接,在加载类的时候,类的字段和方法对应的内存布局之间的连接。
  • 返回值,方法的返回值

线程私有的,就是每个线程都不一样。

  1. 本地方法栈

和虚拟机栈类型,不过这里面具体就要看 native 层的了。

线程私有的,就是每个线程都不一样。

  1. 方法区

类被加载后,类的属性、方法等信息会保存在这里。

一般 new 出来的实例都是放在这里的。其他的部分在方法区里面的常量池。

那,哪些不在堆里面呢???

那些不在堆里面分配的对象实例可能在栈里面,具体的就哟啊说到逃逸分析了,这里

https://juejin.im/post/6844904086010069006

https://zhuanlan.zhihu.com/p/94568794

一个 class 字节码文件里,类的结构是如何的?

类的结构可以粗略看出是一些无符号数和一些表组成的,表里面可以包含其他的表,大概的结构如下。

魔数  
大小版本号 
常量池(表结构) 
访问flag 
父类  
接口列表(表结构) 
字段表(表结构) 
方法表(表结构)  
属性表(表结构)

表结构由表的元素个数 count 和表的内容组成,表的内容可以是无符号数和表。不同的表,表的内容的每一项结构都是固定和相同的。

常量池里面的每一项都是表

JVM 是如何找到一个类的

JVM 是通过 ClassLoader 来加载类的。

ClassLoader 的 loadClass 方法可以让系统找到一个类。

ClassLoader loadClass 的时候用到了双亲委派模式来加载一个类。先判断是否加载过,如果没有加载过,就先交给父类来加载,如果父类也没有加载过,再回到自己,自己去加载。

Java 里面的双亲委派并不是很强制的,可以通过复写 ClassLoader 的 loadClass 方法来破坏这种双亲委派模式,从而达到加载自己的类过程。

ClassLoader 加载类一般是从指定的路径下加载类的,双亲委派模型能保证先优先从顶层的类加载器来加载类,而顶层的类加载器一般是系统提供的,系统提供的类加载器都是加载的指定位置的类库,这样能保证系统类不被篡改。

另外 ClassLoader 的 defindClass 可以通过一个 byte 数组来定义一个类。

JVM 加载类的时候,有哪些过程呢?

类加载可以分为三大步(分别是,载入、连接和初始化),也可以说是 5 个步骤。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FvnTm12W-1609857858288)(https://i.loli.net/2020/08/01/2i3va5CMtkwhWJH.jpg)]

类的加载过程:

  1. 加载 从二进制流加载类,主要做了三件事情
  • a. 通过类的全限定名查找 .class 文件,并生成二进制流
  • b. 解析 .class 文件,主要就是按照 Class 类的结构解析,生成 JVM 特定的数据结构并保存在方法区
  • c. 生成一个 Class 类的实例,后续对这个类的访问可以通过这个 Class 的实例来完成。
  1. 链接,可细分为一下三小步
    1. 验证 校验版本号是否符合要求,高版本 class 不能在低版本 JVM 上运行
    1. 准备 给类的静态变量赋初始值,final 类型赋值。
    1. 解析 主要是把常量池里面的符号引用转为直接引用。
  1. 初始化

主要执行静态代码块、调用构造器的构造方法

类的生命周期,除了加载过程中的 5 个阶段,还有使用卸载 2 种阶段。

Java 内存模型

之前说过,每个线程都有自己的程序计数器、虚拟机栈和本地方法栈。每个线程都是不一样的,还说过 JVM 是虚拟的一个硬件平台。那么 JVM 具体在执行一个线程的时候内存的情况是如何的呢?

线程工作的时候,会给线程分配一个内存空间,我们称之为工作内存,然后还有一个主内存。

线程在工作的时候, JVM 会先从主内存把数据载入工作内存,计算完成以后,在把最后的结果“写回”到主内存。

为什么要这样先载入最后写回?可能是因为载入的指令比较耗时吧。

JVM GC

四种索引

  • 强引用。默认就是强引用,即使内存不够也不会释放。
  • 软引用。SoftRefrence,内存不够的时候,会断开链接,然后释放内存。
  • 弱引用。WeakRefrence,gc 的时候,如果发现了弱引用,就会释放,而不管是否内存不足。需要注意的是,可能需要多次 gc 才有可能找到这个弱引用,因为不同的 gc 清理或者说计算的内存区域不一样。
  • 虚引用。代码里面无法直接使用。无法通过 get 方法获取引用对象。

软引用和弱引用在创建的时候可同时传入一个ReferenceQueue,当引用的对象被回收的时候,ref 实例会被放到 Queue 里面。

GC 的类型

  • GC_FOR_MALLOC 表示在堆上分配内存不足
  • GC_CONCURRENT 表示堆内存达到一定量的值,系统触发
  • GC_BEFOR_OOM 准备抛出 oom 异常
  • GC_EXPLICIT 调用系统方法 system.gc

软引用在前三个 gc 的时候释放,弱引用在创建后,下一次 gc 的时候释放。

回收算法

DVM 和 JVM 区别,或者说是如何优化的

DVM 基于寄存器, JVM 基于栈

基于寄存器的优点是字节指令少,执行效率高,易优化,缺点就是实现复杂

基于栈的有点就是易移植,相对容易实现。缺点就是效率慢,指令多。

ART 虚拟机是在 DVM 上做了优化。但还是基于寄存器的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值