首页 > 技术文章 > JVM结构

Water2Wine 2020-07-30 09:37 原文

JVM主要组成组件:类加载器(classloader),运行时数据区(runtime data areas),执行引擎(execution engine)

1. 类加载器(更多详细信息请移步 https://www.cnblogs.com/Water2Wine/p/13536331.html

从底向上可以分为自定义类加载器->应用程序类加载器->扩展类加载器->启动类加载器

2. 运行时数据区

线程共享:

堆内存:存储对象的实例
方法区:供各线程共享的运行时内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

线程独占:

栈:线程私有,主管Java程序的运行,8中基本类型的变量+对象的引用变量+实例方法都是在函数的栈内存中分配,可以进一步划分为Java栈和本地方法栈
程序计数器:记录了方法之间的调用和执行情况,用来存储指向下一条指令的地址。每一个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码

3. 执行引擎(更多详细信息请移步 https://www.cnblogs.com/Water2Wine/p/12865089.html

执行引擎主要包括JIT即时编译器以及垃圾收集器

垃圾收集器:

Safepoint
安全点顾名思义是指一些特定的位置,当线程运行到这些位置时,线程的一些状态可以被确定,从而确定GC Root的信息,使JVM可以安全的进行一些操作,比如开始GC。
safepoint指的特定位置主要有:

  1. 循环的末尾 (防止大循环的时候一直不进入safepoint,而其他线程在等待它进入safepoint)
  2. 方法返回前
  3. 调用方法的call之后
  4. 抛出异常的位置

STW(Stop The World)
在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;

GC Root
垃圾回收基于GC Root可达性判断。常见的GC Root有如下:
1、通过System Class Loader或者Boot Class Loader加载的class对象
2、处于激活状态的线程
3、栈中的对象
4、JNI栈中的对象
5、JNI中的全局对象
6、正在被用于同步的各种锁对象
7、JVM自身持有的对象,比如系统类加载器等。

垃圾收集算法
标记清除
标记整理
复制

垃圾收集器概况
串行收集器
并行收集器
CMS(并发标记清除收集器)
以上三个的共同点与区别:
共同点:

  1. 年轻代、老年代是独立且连续的内存块;
  2. 年轻代收集使用单eden、双survivor进行复制算法;
  3. 老年代收集必须扫描整个老年代区域且执行标记清楚算法;
  4. 都是以尽可能少而快地执行GC为设计原则。
    不同点:串行是单线程,其他两个都是多线程;串行和并行都是STW式的收集,而CMS在老年代回收上采用了不同的收集方式。主要是初始标记,并发标记,重新标记,并发清除四个步骤。
    G1与以上三组收集器的不同:
  5. G1的设计原则是"首先收集尽可能多的垃圾(Garbage First)"。因此,G1并不会等内存耗尽(串行、并行)或者快耗尽(CMS)的时候开始垃圾收集,而是在内部采用了启发式算法,在老年代找出具有高收集收益的分区进行收集。
  6. G1采用内存分区(Region)的思路,将内存划分为一个个相等大小的内存分区,回收时则以分区为单位进行回收,存活的对象复制到另一个空闲分区中。由于都是以相等大小的分区为单位进行操作,因此G1天然就是一种压缩方案(局部压缩);
  7. G1虽然也是分代收集器,但整个内存分区不存在物理上的年轻代与老年代的区别,也不需要完全独立的survivor(to space)堆做复制准备。G1只有逻辑上的分代概念,或者说每个分区都可能随G1的运行在不同代之间前后切换;
  8. G1的收集都是STW的,但年轻代和老年代的收集界限比较模糊,采用了混合(mixed)收集的方式。即每次收集既可能只收集年轻代分区(年轻代收集),也可能在收集年轻代的同时,包含部分老年代分区(混合收集),这样即使堆内存很大时,也可以限制收集范围,从而降低停顿。
    G1的简单介绍:
  9. G1对Heap的划分
    堆内存被划分为多个大小相等的逻辑heap 区,其中一部分区域被当成老一代收集器相同的角色(eden, survivor, old), 但每个角色的区域个数都不是固定的。
    每个堆Region 的大小在JVM启动时就确定了,JVM通常生成2000个Region,每个Region 大小在1M-32M之间。这些Region会被逻辑映射成Eden, Survivor, 和 old generation(老年代)空间。
  10. 卡片
    在每个分区内部又被分成了若干个大小为512 Byte卡片(Card),标识堆内存最小可用粒度所有分区的卡片将会记录在全局卡片表(Global Card Table)中,分配的对象会占用物理上连续的若干个卡片,当查找对分区内对象的引用时便可通过记录卡片来查找该引用对象(见RSet)。每次对内存的回收,都是对指定分区的卡片进行处理。
  11. 已记忆集合(RSet)
    在串行和并行收集器中,GC通过整堆扫描,来确定对象是否处于可达路径中。然而G1为了避免STW式的整堆扫描,在每个分区记录了一个已记忆集合(RSet),内部类似一个反向指针,记录引用分区内对象的卡片索引。当要回收该分区时,通过扫描分区的RSet,来确定引用本分区内的对象是否存活,进而确定本分区内的对象存活情况。
  12. 收集集合(CSet)
    收集集合(CSet)代表每次GC暂停时回收的一系列目标分区。在任意一次收集暂停中,CSet所有分区都会被释放,内部存活的对象都会被转移到分配的空闲分区中。

推荐阅读