JVM学习《垃圾回收算法和垃圾回收器》

目录

1.垃圾回收算法

1.1 标记-清除算法

1.2 复制算法

1.3 标记-整理算法

1.4 分代收集算法

2.垃圾回收器

2.1 熟悉一下垃圾回收的一些名词

2.2 垃圾回收器有哪些?

 2.3 Serial收集器

2.4 Parallel Scavenge收集器

2.5 ParNew收集器

2.6  CMS收集器


1.垃圾回收算法

  • 标记-复制算法:将内存分为两块,每次使用一块,当内存用完时,将存活的对象复制到另一块,并清理使用过的空间。
  • 标记-清除算法:分为标记和清除阶段,标记存活的对象,然后统一回收未标记的对象。
  • 标记-整理算法:类似标记-清除算法,但在标记后将存活的对象移动到一端,然后清理边界外的内存。
  • 分代收集理论:根据对象的存活周期将内存分为新生代和老年代,并为它们选择合适的垃圾收集算法。

1.1 标记-清除算法
  • 标记无用对象,然后进行清除回收。

  • 标记-清除算法(Mark-Sweep)是一种常见的基础垃圾收集算法,它将垃圾收集分为两个阶段:

    • 标记阶段:标记出可以回收的对象。
    • 清除阶段:回收被标记的对象所占用的空间。
  • 标记-清除算法之所以是基础的,是因为后面讲到的垃圾收集算法都是在此算法的基础上进行改进的。

  • 优点:实现简单,不需要对象进行移动。

  • 缺点:标记、清除过程效率低,产生大量不连续的内存碎片,提高了垃圾回收的频率。

  • 标记-清除算法的执行的过程如下图所示

在这里插入图片描述

 

1.2 复制算法
  • 为了解决标记-清除算法的效率不高的问题,产生了复制算法。它把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾收集时,遍历当前使用的区域,把存活对象复制到另外一个区域中,最后将当前使用的区域的可回收的对象进行回收。

  • 优点:按顺序分配内存即可,实现简单、运行高效,不用考虑内存碎片。

  • 缺点:可用的内存大小缩小为原来的一半,对象存活率高时会频繁进行复制。

  • 复制算法的执行过程如下图所示

在这里插入图片描述

 

1.3 标记-整理算法
  • 在新生代中可以使用复制算法,但是在老年代就不能选择复制算法了,因为老年代的对象存活率会较高,这样会有较多的复制操作,导致效率变低。标记-清除算法可以应用在老年代中,但是它效率不高,在内存回收后容易产生大量内存碎片。因此就出现了一种标记-整理算法(Mark-Compact)算法,与标记-整理算法不同的是,在标记可回收的对象后将所有存活的对象压缩到内存的一端,使他们紧凑的排列在一起,然后对端边界以外的内存进行回收。回收后,已用和未用的内存都各自一边。

  • 优点:解决了标记-清理算法存在的内存碎片问题。

  • 缺点:仍需要进行局部对象移动,一定程度上降低了效率。

  • 标记-整理算法的执行过程如下图所示

在这里插入图片描述

 

1.4 分代收集算法
  • 当前商业虚拟机都采用 分代收集的垃圾收集算法。分代收集算法,顾名思义是根据对象的存活周期将内存划分为几块。一般包括年轻代老年代永久代,如图所示:(后面有重点讲解)

在这里插入图片描述

作者:小杰要吃蛋
链接:https://juejin.cn/post/6844904125696573448
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.垃圾回收器

2.1 熟悉一下垃圾回收的一些名词

      新生代收集(Minor GC/Young GC):只是新生代的垃圾收集

  老年代收集(Major GC/Old GC):只是老年代的垃圾收集

  混合收集(Mixed GC):收集整个新生代以及部分老年代的垃圾收集,目前只有 G1 GC 会有这种行为

  整堆收集(Full GC):收集整个 Java 堆和方法区的垃圾

2.2 垃圾回收器有哪些?

 2.3 Serial收集器

Serial(串行)收集器是最基本、历史最悠久的垃圾收集器了。大家看名字就知道这个收集器是一个单线程收集器了。它的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他 所有的工作线程( "Stop The World" ),直到它收集结束。

 新生代采用复制算法,老年代采用标记-整理算法。

 虚拟机的设计者们当然知道Stop The World带来的不良用户体验,所以在后续的垃圾收集器设计中停顿时间在不断缩短(仍然还有停 顿,寻找最优秀的垃圾收集器的过程仍然在继续)。 、

但是Serial收集器有没有优于其他垃圾收集器的地方呢?当然有,它简单而高效(与其他收集器的单线程相比)。Serial收集器由于没 有线程交互的开销,自然可以获得很高的单线程收集效率

Serial Old收集器是Serial收集器的老年代版本,它同样是一个单线程收集器。它主要有两大用途:一种用途是在JDK1.5以及以前的 版本中与Parallel Scavenge收集器搭配使用,另一种用途是作为CMS收集器的后备方案。

2.4 Parallel Scavenge收集器

Parallel收集器其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等 等)和Serial收集器类似。默认的收集线程数跟cpu核数相同,当然也可以用参数(-XX:ParallelGCThreads)指定收集线程数,但是一般 不推荐修改。

Parallel Scavenge收集器关注点是吞吐量(高效率的利用CPU)。CMS等垃圾收集器的关注点更多的是用户线程的停顿时间(提高 用户体验)。所谓吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值。 Parallel Scavenge收集器提供了很多参数 供用户找到最合适的停顿时间或最大吞吐量,如果对于收集器运作不太了解的话,可以选择把内存管理优化交给虚拟机去完成也是一 个不错的选择。

新生代采用复制算法,老年代采用标记-整理算法。

Parallel Old收集器是Parallel Scavenge收集器的老年代版本。使用多线程和“标记-整理”算法。在注重吞吐量以及CPU资源的场 合,都可以优先考虑 Parallel Scavenge收集器和Parallel Old收集器(JDK8默认的新生代和老年代收集器)。

2.5 ParNew收集器

ParNew收集器其实跟Parallel收集器很类似,区别主要在于它可以和CMS收集器配合使用。

新生代采用复制算法

2.6  CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使 用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。 从名字中的Mark Sweep这两个词可以看出,CMS收集器是一种 “标记-清除”算法实现的,它的运作过程相比于前面几种垃圾收集 器来说更加复杂一些。整个过程分为四个步骤:

初始标记: 暂停所有的其他线程(STW),并记录下gc roots直接能引用的对象,速度很快。

并发标记: 并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程, 这个过程耗时较长但是不需要停顿用户线 程, 可以与垃圾收集线程一起并发运行。因为用户程序继续运行,可能会有导致已经标记过的对象状态发生改变。

重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录(主要 是处理漏标问题),这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短。主要用到三色标记里的增量 更新算法(见下面详解)做重新标记。

并发清理: 开启用户线程,同时GC线程开始对未标记的区域做清扫。这个阶段如果有新增对象会被标记为黑色不做任何处理(见下 面三色标记算法详解)。 并发重置:重置本次GC过程中的标记数据。

三色标记 :

在并发标记的过程中,因为标记期间应用线程还在继续跑,对象间的引用可能发生变化,多标和漏标的情况就有可能发生。漏标的问 题主要引入了三色标记算法来解决。

三色标记算法是把Gc roots可达性分析遍历对象过程中遇到的对象, 按照“是否访问过”这个条件标记成以下三种颜色:

黑色: 表示对象已经被垃圾收集器访问过, 且这个对象的所有引用都已经扫描过。 黑色的对象代表已经扫描过, 它是安全存活 的, 如果有其他对象引用指向了黑色对象, 无须重新扫描一遍。 黑色对象不可能直接(不经过灰色对象) 指向某个白色对象。

灰色: 表示对象已经被垃圾收集器访问过, 但这个对象上至少存在一个引用还没有被扫描过。

表示对象尚未被垃圾收集器访问过。 显然在可达性分析刚刚开始的阶段, 所有的对象都是白色的, 若在分析结束的阶段, 仍然是白色的对象, 即代表不可达

CMS是一款优秀的垃圾收集器,主要优点:并发收集、低停顿。但是它有下面几个明显的缺点:

1. 对CPU资源敏感(会和服务抢资源);

2. 无法处理浮动垃圾(在并发标记和并发清理阶段又产生垃圾,这种浮动垃圾只能等到下一次gc再清理了);

3. CMS使用的回收算法“标记-清除”算法会导致收集结束时会有大量空间碎片产生,当然通过参数 XX:+UseCMSCompactAtFullCollection可以让jvm在执行完标记清除后再做整理

4. 执行过程中的不确定性,会存在上一次垃圾回收还没执行完,然后垃圾回收又被触发的情况,特别是在并发标记和并发清理阶 段会出现,一边回收,系统一边运行,也许没回收完就再次触发full gc,也就是"concurrent mode failure",此时会进入stop the world,用serial old垃圾收集器来回收 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/34955.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

波特图方法

在电路设计中,波特图为最常用的稳定性余量判断方法,波特图的根源是如何来的,却鲜有人知。 本章节串联了奈奎斯特和波特图的渊源,给出了其对应关系和波特图相应的稳定性余量。 理论贯通,不在于精确绘…

【Java】2、集合框架 JCF

目录 CollectionListArrayList扩容机制System.arraycopy() 和 Arrays.copyOf()方法 LinkedList Set MapHashMap *重点: 底层机制(源码)应用场景 好处: 数组(长度不可改,同一类型,增删不便&#…

P5461 赦免战俘

P5461 赦免战俘 #include <iostream> using namespace std; #include <algorithm> #include <vector> #include <cmath> void pardon(auto & matrix,int x,int y,int size){if(size 1) return;int half size / 2;for(int i x;i < x half;i …

GoTrackIt应用指南:共享单车时空轨迹可视化

GoTrackIt平台集成了对 Kepler.gl 可视化工具的部分功能进行了封装&#xff0c;通过引入 KeplerVis 类&#xff0c;显著简化了地理空间数据分析与展示的过程。利用这一类&#xff0c;开发者和数据分析师能够在网页端快速实现复杂地理数据的动态可视化&#xff0c;而无需深入掌握…

LeetCode 力扣 热题 100道(十五)搜索插入位置(C++)

给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 代码如下所示&#xff1a; class Solution { public:int searchIns…

JS中递归函数的理解及展开运算符在递归种的运用理解

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>递归函数</title> </head> <body> <script>const list ["你好", "吃饭了吗",["好",[[&qu…

vue中.sync修饰符的用法

一、什么是.sync修饰符 在Vue.js中&#xff0c;.sync 修饰符用于创建一个双向绑定的 prop。它使子组件能够更新父组件的 prop 值&#xff0c;实现父子组件之间的双向数据同步。具体来说&#xff0c;.sync 修饰符主要有以下几个功能&#xff1a; 简化双向绑定&#xff1a; 使用…

element Plus中 el-table表头宽度自适应,不换行

在工作中&#xff0c;使用el-table表格进行开发后&#xff0c;遇到了小屏幕显示器上显示表头文字会出现换行展示&#xff0c;比较影响美观&#xff0c;因此需要让表头的宽度变为不换行&#xff0c;且由内容自动撑开。 以下是作为工作记录&#xff0c;用于demo演示教程 先贴个…

rockit 学习、开发笔记(五)(VDEC)

前言 后面由于业务需求有rockit编解码的功能开发&#xff0c;这里我是第一次接触编解码&#xff0c;所以后续有些概念表述可能不太清楚&#xff0c;请各位多多包涵。 先来说一下解码模块的使用&#xff0c;rockit中的解码模块是VDEC&#xff0c;如果想要开发rockit的vdec可能…

unicloud微信小程序云端一体项目DEMO

最近应客户需求&#xff0c;做了一个产品展示的云开发小程序&#xff0c;从了解云开发到应用到实际项目的产品demo&#xff0c;希望大家能从中获取到对自己有用的东西。 说下心得体会吧&#xff0c;一般小项目用这种云开发确实会减少很多开发成本&#xff0c;人力成本&#xf…

图的创建和基础操作(数据结构实验作业)

上面是我的实验作业要求&#xff1a;&#xff08;看不到的同学&#xff0c;移步&#xff1a;https://gitee.com/young-lion/picture-bed/raw/master/202412051939715.png&#xff09; 下面的代码使用的是go语言&#xff1a; package mainimport ("fmt" )// 访问标记…

flex布局容易忽略的角色作用

目录 清除浮动 作用于行内元素 flex-basis宽度 案例一&#xff1a; 案例二&#xff1a; 案例三&#xff1a; flex-grow设置权重 案例一&#xff1a; 案例二&#xff1a; 简写flex-grow:1 0 auto; flex作为一维布局,行和列的使用&#xff0c;忽略的小角色&#xff0c;大…

javascript-svg-在圆环上拖动并选中区域

目录 问题描述解决思路代码结构 问题描述 假设我某个页面上使用了<svg>&#xff0c;其中包括一个<circle>。我希望实现的是&#xff1a;在circle上点击某个位置后&#xff0c;拖动&#xff0c;出现圆弧状阴影。实现效果为&#xff1a; 解决思路 要实现这个效果…

Android 使用 Canvas 和 Paint 实现圆形图片

学习笔记 效果展示: 全部代码: public class YuanActivity extends AppCompatActivity {private ActivityYuanBinding binding;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 通过 DataBinding 获取布局文件binding …

python怎么将字母大写

Python中有三种将字母转换为大写的方法&#xff1a;upper()、capitalize()、title()。 下面通过实例给大家介绍具体用法&#xff1a; str "www.php.com" print(str.upper()) # 把所有字符中的小写字母转换成大写字母 print(str.lower()) # 把所有字…

鸿蒙Next星河版高级用例之网络请求和自适应布局以及响应式布局

目录&#xff1a; 1、发起网络请求的两种方式第一种使用httpRequest发送http的请求&#xff1a;1.1、在进行网络请求前&#xff0c;您需要在module.json5文件中申明网络访问权限1.2、GET 请求1.3、POST请求1.4、处理响应的结果第二种使用axios发送http的请求&#xff1a;1.1、在…

ClouderaManager 集群搭建

前提&#xff1a;服务器之前做过域名映射、免密登录 ClouderaManager 集群 1. 组件分布规划 服务器服务器h1zk、hdfs(dn)、yarn(nm)、spark、kafka、flumeh2hdfs(nn-standy)、yarn(rm-active)、sparkh3hdfs(nn-active)、yarn(rm-standy)、hive、sparkh4zk、hdfs(dn)、yarn(n…

如何获取谷歌新闻API密钥?

在信息获取和新闻传播领域&#xff0c;快速获取最新的新闻动态至关重要。谷歌新闻API为开发者提供了强大的工具&#xff0c;能够方便地集成全球各类新闻内容。通过使用该API&#xff0c;开发者可以实现对新闻的实时访问和管理&#xff0c;为用户提供丰富的信息服务。本文将指导…

IP 协议

IP协议 一、介绍1、IP协议2、IPv43、IPv6 二、主要功能三、协议格式1、示意图2、说明 四、网段划分1、介绍2、目的3、方法4、步骤 五、基于类别的IP地址分配方式1、示意图2、范围 六、CIDR1、介绍2、组成3、优点4、示意图 七、子网掩码1、介绍2、功能3、表示方法4、CIDR表示法5…

数据结构 (23)并查集与等价类划分

一、并查集 并查集&#xff08;Union-Find Set或Disjoint Set&#xff09;是一种数据结构&#xff0c;用于处理一些不相交集合&#xff08;disjoint sets&#xff09;的合并及查询问题。它通常表示为森林&#xff0c;并用数组来实现&#xff08;类似于二叉堆&#xff09;。在并…