设为首页 加入收藏

TOP

Java虚拟机-------垃圾回收机机制(一)
2019-09-03 01:43:41 】 浏览:27
Tags:Java 虚拟 ------- 垃圾 回收 机制


概述

jvm中的堆图

 


在了解 垃圾回收器 之前,首先得了解一下垃圾回收器的几个名词。

1. 吞吐量
CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值。比如说虚拟机总运行了 100 分钟,用户代码 时间 99 分钟,垃圾回收 时间 1 分钟,那么吞吐量就是 99%。

吞吐量 = 运行用户代码时间/(运行用户代码时间 + 垃圾回收时间)

2. 停顿时间
停顿时间 指垃圾回收器正在运行时,应用程序 的 暂停时间。对于 独占回收器 而言,停顿时间可能会比较长。使用 并发回收器 时,由于垃圾回收器和应用程序 交替运行,程序的 停顿时间 会变短,但是,由于其 效率 很可能不如独占垃圾回收器,故系统的 吞吐量 可能会较低。

3. GC的名词
3.1. 新生代GC(Minor GC)
指发生在 新生代 的垃圾回收动作,因为 Java 对象大多都具备 朝生夕死 的特性,所以 Minor GC 通常 非常频繁,一般回收速度也比较快。

3.2. 老年代GC(Major GC)
指发生在 老年代 的垃圾回收动作,出现了 Major GC,经常会伴随至少一次的 Minor GC(发生这种情况,那么 整个堆 都 GC 一遍,通常称为 Full GC)。Major GC 的速度一般会比 Minor GC 慢 10 倍以上。

4. 并发与并行
4.1. 串行(Serial)
单线程 进行垃圾回收工作,但此时 用户线程 仍然处于 等待状态。

4.2. 并发(Concurrent)
这里的并发指 用户线程 与 垃圾回收线程 交替执行。

4.3. 并行(Parallel)
这里的并行指 用户线程 和多条 垃圾回收线程 分别在不同 CPU 上同时工作。

 

垃圾回收算法


1. 根搜索算法
根搜索算法 是从 离散数学 中的图论引入的,程序把所有引用关系看作一张图,从一个节点 GC ROOT 开始,寻找对应的 引用节点,找到这个节点后,继续寻找 这个节点 的 引用节点。当所有的引用节点寻找完毕后,剩余的节点 则被认为是 没有被引用到 的节点,即 无用 的节点。

 

目前 Java 中可以作为 GC ROOT 的对象有:

虚拟机栈 中引用的对象(本地变量表);

方法区 中 静态变量 引用的对象;

方法区 中 常量 引用的对象;

本地方法栈 中引用的对象(Native 对象)。

基本所有 GC 算法都引用 根搜索算法 这种概念。

 

2. 标记 - 清除算法
标记-清除算法 从 根集合 进行扫描,对 存活的对象 进行 标记。标记完毕后,再扫描整个空间中 未被标记 的对象进行 直接回收。

 标记-清除算法 不需要进行 对象的移动,并且仅对 不存活 的对象进行处理,在 存活 的对象 比较多 的情况下 极为高效。但由于 标记-清除算法 直接回收不存活的对象,并没有对还存活的对象进行 整理,因此会导致 内存碎片,影响内存的使用

 

3. 复制算法
复制算法 将内存划分为 两个区间,使用此算法时,所有 动态分配 的对象都只能分配在 其中一个 区间(活动区间),而 另外一个 区间(空间区间)则是 空闲 的。

复制算法 同样从 根集合 扫描,将 存活 的对象 复制 到 空闲区间。当扫描完毕活动区间后,会的将 活动区间 一次性全部 回收。此时原本的 空闲区间 变成了 活动区间。下次 GC 时候又会重复刚才的操作,以此循环。

 

复制算法 在存活对象 比较少 的时候,极为高效,但是带来的成本是 牺牲一半的内存空间 用于进行 对象的移动。所以 复制算法 的使用场景,必须是对象的 存活率非常低 才行。最重要的是,我们需要克服 50% 的 内存浪费

 

4. 标记 - 整理算法
标记-整理算法 采用 标记-清除算法 一样的方式进行对象的 标记,但在回收 不存活的对象 占用的空间后,会将所有 存活的对象 往 左端空闲空间 移动,并更新对应的指针。

 

标记-整理 是在 标记-清除 之上,又进行了 对象的移动排序整理,因此 成本更高,但却解决了 内存碎片 的问题

JVM 为了 优化内存 的回收,使用了 分代回收 的方式。

对于 新生代内存 的回收(Minor GC)主要采用 复制算法

而对于 老年代内存 的回收(Major GC),大多采用 标记-整理算法。

 

垃圾回收器

 

1. 七种垃圾回收器概述


在 JVM 中,具体实现有 Serial、ParNew、Parallel Scavenge、CMS、Serial Old(MSC)、Parallel Old、G1 等。在下图中,你可以看到 不同垃圾回收器 适合于 不同的内存区域,如果两个垃圾回收器之间 存在连线,那么表示两者可以 配合使用。

 

如果当 垃圾回收器 进行垃圾清理时,必须 暂停 其他所有的 工作线程,直到它完全收集结束。我们称这种需要暂停工作线程才能进行清理的策略为 Stop-the-World。以上回收器中, Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old 均采用的是 Stop-the-World 的策略。

 

图中有 7 种不同的 垃圾回收器,它们分别用于不同分代的垃圾回收。

新生代回收器:Serial、ParNew、Parallel Scavenge

老年代回收器:Serial Old、Parallel Old、CMS

整堆回收器:G1

两个 垃圾回收器 之间有连线表示它们可以 搭配使用,可选的搭配方案如下:

新生代 老年代
Serial Serial Old
Serial CMS
ParNew Serial Old
ParNew CMS
Parallel Scavenge Serial Old
Parallel Scavenge Parallel Old
G1 G1


2. 单线程垃圾回收器

2.1. Serial(-XX:+UseSerialGC)
Serial 回收器是最基本的 新生代 垃圾回收器,是 单线程 的垃圾回收器。由于垃圾清理时,Serial 回收器 不存在 线程间的切换,因此,特别是在单 CPU 的环境下,它的 垃圾清除效率 比较高。对于 Client 运行模式的程序,选择 Serial 回收器是一个不错的选择。

Serial 新生代回收器 采用的是 复制算法。

2.2. Serial Old(-XX:+UseSerialGC)
Serial Old 回收器是 Serial 回收器的 老生代版本,属于 单线程回收器,它使用 标记-整理 算法。对于 Server 模式下的虚拟机,在 JDK1.5 及其以前,它常与 Parallel Scavenge 回收器配合使用,达到较好的 吞吐量,另外它也是 CMS 回收器在 Concurrent Mode Failure 时的 后备方案。

Serial Old 老年代回收器 采用的是 标记 - 整理算法。

 

3. 多线程垃圾回收器(吞吐量优先


3.1. ParNew(-XX:+UseParNewGC)


ParNew 回收器是在 Serial 回收器的基础上演化而来的,属于 Serial 回收器的 多线程版本,同样运行在 新生代区域。在实现上,两者共用很多代码。在不同运行环境下,根据 CPU 核数,开启 不同的线程数,从而达到 最优 的垃圾回收效果。对于那些 Server 模式的应用程序,如果考虑采用 CMS 作为 老生代回收器 时,ParNew 回收器是一个不错的选择。

 ParNew 新生代回收器 采用的是 复制算法。

 

3.2. Parallel Scavenge(-XX:+UseParallelGC)


和 ParNew 回收一样,Parallel Scavenge 回收器也是运行在 新生代区域,属于 多线程 的回收器。但不同的是,ParNew 回收器是通过控制 垃圾回收 的 线程数 来进行参数调整,而 Parallel Sca

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Linux 中 IDEA 不能调试(Debug)项.. 下一篇键盘录入之录入整数

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目