Java 虚拟机 ( 简读版 )

2021-07-14  本文已影响0人  张云飞Vir

1. 背景

本文聊聊Java 虚拟机的一些知识。

2.知识

Java Virtual Machine(Java虚拟机,简称JVM)是一个抽象的计算机器。像真正的计算机器一样,它有一个指令集并在运行时操纵各种内存区域。

拆分几个过程来理解概貌

JVM 使得 Java程序 与 操作系统(及硬件)保持独立性。JVM 并不依赖 Java 编程语言 ,它只知道一种特定的二进制格式,即class文件格式。一个class文件包含着Java虚拟机指令(或字节码)和符号表,以及其它辅助信息。

拆分几个过程来理解:

JVM 具体可以由 ”JVM 规范“ 定义,有很多厂商提供了JVM的实现。比如:Oracle 的 JVM 之一名为 HotSpot,另一个继承自BEA Systems 的是JRockit。Android 使用了 Dalvik虚拟机,ART虚拟机。

3. JVM 核心组成部分(三大项)

也就是说 JVM 有这些组成部分:

重点这三项,我们慢慢讲。

3.1、字节码指令

JVM 具有针对以下任务组的字节码指令规范:

这些指令是一些操作任务,被加载到JVM后可以被执行。

3.2、字节码解释器和即时编译器

(1) 字节码解释器 ( bytecode interpreter )
字节码解释器用于将字节码解析成计算机能执行的语言,一台计算机有了 Java 字节码解释器后,它就可以运行任何 Java 字节码程序。同样的 Java 程序就可以在具有了这种解释器的硬件架构的计算机上运行,实现了“跨平台”。

(2) 即时编译器 ( just-in-time compiler,JIT )
JIT 编译器可以在执行程序时将 Java 字节码翻译成本地机器语言

一般来讲,Java 字节码经过 字节码解释器执行时,执行速度总是比编译成本地机器语言的同一程序的执行速度慢。而 即时编译器 在执行程序时将 Java 字节码翻译成本地机器语言,以显著加快整体执行时间。

3.3、虚拟机架构

JVM 操作内存有这些:

为了兼容性。每个特定的主机操作系统都需要自己的 JVM 和运行时实现。虽然实际实现可能不同,但是 在语义上都以相同的方式解释字节码。

还与重要的垃圾回收机制,我们后面再讲。

3.4 类加载器 ( Class loader )

JVM 字节码的基本单位是。类加载器 ( Class loader ) 用于识别和加载符合 Java的 Class 文件格式的内容。

类加载器按顺序执行下面三个活动:

一般来说,有两种类型的类加载器:

每个 Java 虚拟机实现都必须有一个引导类加载器 ( bootstrap class loader ),能够加载受信任的类,以及一个扩展类加载器或应用程序类加载器 ( application class loader)。

3.5 JVM 语言

有很多种 JVM 语言可以选择,比如 Groovy、Scala和 Kotlin 等,这些语言编写的代码都可以被编译成 字节码后 在JVM 上运行。

4. 垃圾回收器( Garbage Collection, GC )

垃圾收集( GC ) 是一种自动内存管理形式。作用是将内存中不再被使用的对象进行回收,由垃圾收集器执行“垃圾收集策略”执行回收工作。

也就是有这两点:

下面再分别描述这两点。

4.1 常见的垃圾回收策略

(1) 什么样的对象需要被回收?
判断对象是否存活一般有两种方式:

(2) 垃圾回收的算法/策略
1、“标记-清除" 算法 (mark-sweep)
分 “标记” 和 “清除” 两个阶段:首先标记处所需要回收的对象,在标记完成后统一回收所有被标记的对象。

标记-清除
可以看到,产生了大量不连续的内存碎片。

2、“复制” 算法(Copying),它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。


复制算法

代价是可用区域缩小为原来的一半。

3、“标记-压缩" 算法 (mark-compact)算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存


标记-压缩

4、分代收集策略
HotSpot 是 Oracle 一个JVM ,为了加速代码执行,它使用了分代堆 ( generational heap )。

它根据对象存活周期的不同将 '内存堆 (Heap)' 分为:

这样就可以根据各个年代的特点采用不同的收集算法,比如 针对新生代的区域使用标记-清除算法,针对老年代区域使用 标记-压缩算法。实际不同的JVM实现也有多种方式组合。

(在新的版本中已经将永久代废弃,引入了元空间的概念,永久代使用的是JVM内存而元空间直接使用物理内存)。

新生代中的对象在每次GC时都会有大量对象被回收,少量存活。老年代中的对象存活率较高。

新生代又分为三个区:

在分配时:

4.2 垃圾回收器

垃圾回收器是垃圾回收策略的具体实现,有下面这些:

(1) Serial ( 串行收集器 )

串行收集器 是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。垃圾收集的过程中会Stop The World(服务暂停)。新生代、老年代使用串行回收;新生代复制算法、老年代标记-压缩算法。

Serial收集器的多线程版本 叫做 ParNew 收集器,它支持并行。它的新生代采用并行方式,老年代串行;新生代复制算法、老年代标记-压缩

(2) Parallel (并行收集器)

Parallel收集器更关注系统的吞吐量。它会根据当前系统的运行情况收集性能监控信息,动态调整参数以提供最合适的停顿时间或最大的吞吐量;也可以通过参数控制GC的时间不大于多少毫秒或者比例;新生代复制算法、老年代标记-压缩。

(3) CMS ( Concurrent mark sweep collector ,并发收集器)

当前 Java Web 应用重视服务的响应,希望停顿时间短。CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。

CMS收集器的内存回收过程是与用户线程一起并发地执行的,它会先执行一次标记过程,后在标记扫描一次因用户程序继续运作而导致标记产生变动的那一部分。

整个过程分为4个步骤,包括:

其中初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录

(4) G1收集器

G1收集器有以下特点:

使用G1收集器时,Java堆的内存布局与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离了。

5.参考:

Oracle 的 Java 虚拟机规范
https://docs.oracle.com/javase/specs/jvms/se8/html/
维基百科
https://en.m.wikipedia.org/wiki/Java_virtual_machine

https://www.cnblogs.com/haojile/p/12578470.html
https://blog.csdn.net/qq_38163244/article/details/109551205
https://mp.weixin.qq.com/s?__biz=MzI4NDY5Mjc1Mg==&mid=2247483952&idx=1&sn=ea12792a9b7c67baddfaf425d8272d33&chksm=ebf6da4fdc815359869107a4acd15538b3596ba006b4005b216688b69372650dbd18c0184643&scene=21#wechat_redirect
https://zhuanlan.zhihu.com/p/34426768
https://blog.csdn.net/qq_41701956/article/details/81664921

END

上一篇下一篇

猜你喜欢

热点阅读