垃圾收集器ParNewCMS与底层三色标记算法详解

垃圾收集算法

在这里插入图片描述

分代收集理论

当前虚拟机的垃圾收集都是采用分代收集算法,这种算法没有什么新思想,只是依据对象的存活周期不同将内存分为几块.一般将Java堆分为新生代和老年代,这样就可以根据各个年代的特点选择合适的垃圾收集算法.

比如在新生代中,每次收集都会有大量对象(近99%)死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集.而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择"标记-清除"或"标记-整理"算法进行垃圾收集.注意:“标记-清除"或"标记-整理算法会比复制算法慢10倍以上”.

标记-复制算法

为了解决效率问题,"复制"收集算法出现了.它可以将内存分为大小相同的两块,每次使用其中的一块.当这一块内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉.这样就每次的内存回收都是对内存区间的一半进行回收.

在这里插入图片描述

标记-清除算法

算法分为"标记"和"清除"阶段;标记存活的对象,统一回收所有未被标记的对象(一般选择这种);也可以反过来,标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象.它是最基础的收集算法,比较简单,但是会带来两个明显的问题:

  1. 效率问题:如果需要标记的对象太多,效率不高
  2. 空间问题:标记清除后会产生大量不连续的碎片

在这里插入图片描述

标记-整理算法

根据老年代的特点特出的一种标记算法,标记过程仍然与"标记-清除"算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存.

在这里插入图片描述

垃圾收集器

在这里插入图片描述

如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现.

虽然我们对各个收集器进行比较,但并非为了挑选出一个最好的收集器.因为直到现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,我们能做的就是根据具体的应用场景选择适合自己的垃圾收集器.试想一下:如果有一种四海之内,任何场景下都适用的完美收集器存在,那Java虚拟机就不会实现那么多不同的垃圾收集器了.

Serial收集器

-XX:+UseSerialGC -XX:+UseSerialOldGC

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

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

在这里插入图片描述

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

但是Serial收集器有没有优于其他垃圾收集器的地方呢?

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

Serial Old收集器是Serial收集器的老年代版本,它同样是一个单线程收集器,主要有以下两种用途:

  • 在JDK1.5及以前的版本中与Parallel Scavenge收集器搭配使用
  • 作为CMS收集器的后备方案

Parallel Scavenge收集器

年轻代:-XX:UseParallelGC

老年代:-XX:UseParallelOldGC

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

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

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

在这里插入图片描述

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

ParNew收集器

-XX:+UseParNewGC

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

新生代采用复制算法

在这里插入图片描述

它是许多运行在Server模式下的虚拟机的首要选择,除了Serial收集器外,只有它能与CMS收集器配合工作

CMS收集器

-XX:+UseConcMarkSweepGC

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器.它非常符合在注重用户体验的应用上使用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作.

从名字中 Mark Sweep 这两个词可以看出,CMS收集器是一种 标记-清除 算法实现的,它的运作过程相比于前面集中垃圾收集器来说更加复杂一些.整个过程分为四个步骤:

  • 初始标记:暂停所有的其他线程(STW),并记录下GC Roots 直接能引用的对象,速度很快.
  • 并发标记:并发标记就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行.因为用户程序继续运行,可能会有导致已经标记过的对象状态发生改变
  • 重新标记:重新标记阶段就是为了修正并发标记期间因为用户程序继续运作而导致标记产生变动的那一部分对象的标记记录(主要是处理漏标问题),这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短.主要用到三色标记里的增量更新算法做重新标记
  • 并发重置:重置本次GC过程中的标记数据

在这里插入图片描述

从它的名字就可以看出它是一款优秀的垃圾收集器,主要有点:**并发收集,低停顿.**但是它有下面几个明显的缺点:

  • 对CPU资源敏感(会和应用程序抢资源)
  • 无法处理 浮动垃圾 (在并发标记和并发清理阶段又产生垃圾,这种浮动垃圾只能等到下一次GC再清理了)
  • 使用的回收算法"标记-清除"算法会导致收集结束时会有 大量的空间碎片产生,当然通过参数-XX:+UseCMSCompactAtFullCollection让JVM在执行完标记清除后在做整理
  • 执行过程中的不确定性,会存在上一次垃圾回收还没执行完,然后垃圾回收又被触发的情况,特别是在并发标记和并发清理阶段会出现,一边回收,系统一边运行,也许还没回收完就再次触发Full GC,也就是"concurrent mode failure",此时会进入STW,用Serial Old垃圾收集器来回收

CMS相关核心参数

  1. -XX:+UseConcMarkSweepGC:启用CMS
  2. -XX:ConcGCThreads:并发的GC线程数
  3. -XX:UseCMSCompactAtFullConllection:FullGC之后做压缩整理(减少碎片)
  4. -XX:CMSFullGCBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC都会压缩一次
  5. -XX:CMSInitiatingOccupancyFraction:当老年代使用达到该比例会触发Full GC(默认92.当老年代使用空间达到92%以后触发Full GC)
  6. -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,JVM仅在第一次使用设定值,后续会动态调整
  7. -XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次Minor GC,降低CMS GC标记阶段(也会对年轻代一起做标记,如果在Minor GC就清除了很多垃圾对象,标记阶段就会减少一些标记时间)时的开销,一般CMS的GC耗时80%都在标记阶段
  8. -XX:+CMSParallellnitialMarkEnabled:表示在初始标记阶段多线程执行,缩短STW
  9. -XX:+CMSParallelRemarkEnabled:在重新标记阶段多线程执行,缩短STW

垃圾收集算法底层实现

三色标记

在并发标记的过程中,因为标记期间应用线程还在继续跑,对象间的引用可能发生变化,多标和漏标的情况就有可能发生.漏标的问题主要引入了三色标记算法来解决.
三色标记算法是把GC Roots可达性分析遍历对象过程中遇到的对象,按照"是否访问过"这个条件标记成以下三种颜色:

  • 黑色:表示对象已经被垃圾收集器访问过,且这个对象的所有引用都已经扫描过,黑色的对象代表已经扫描过,它是安全存活的,如果有其他对象引用指向了黑色对象,无须重新扫描一遍.黑色对象不可能直接(不经过灰色对象)指向某个白色对象.
  • 灰色:表示对象已经被垃圾收集器访问过,但这个对象至少存在一个引用还没有被扫描过.
  • 白色:表示对象尚未被垃圾收集器访问过.显示在可达性分析刚刚开始的阶段,所有对象都是白色的,若在分析结束的阶段,仍然是白色的对象,即代表不可达
public class ThreeColorRemarkDemo {

    public static void main(String[] args) {
        A a = new A();
        // 开始做并发标记
        D d = a.b.d; // 读
        a.b.d = null; // 写
        a.d = d; // 写
    }
}

class A{
    B b = new B();
    D d = null;
}

class B{
    C c = new C();
    D d = new D();
}

class C{}

class D{}

在这里插入图片描述

漏标问题复现:

假设A a = new A();后开始做并发标记,从a指向A.从A执行B.从B指向C,此时将A和C记为黑色.B由于还没有扫描到D记为灰色.
在这里插入图片描述
a.b.d = null;将B和D之间的引用给干掉了.
在这里插入图片描述
在并发标记的过程中,应用线程是可以正常执行的.代码此时将a.d = d;但是由于A是黑色.在后面重新标记的过程中是不会扫描黑色的就会出现漏标的问题.

多标-浮动垃圾

在并发标记过程中,如果由于方法运行结束导致部分局部变量(GC Roots)被销毁,这个GC Roots引用的对象之前又被扫描过(被标记为非垃圾对象).那么本轮GC不会回收这部分内存,这部分本该回收但是没有回收的内存,被称之为"浮动垃圾",浮动垃圾并不会影响垃圾回收的正确性,只是需要等到下一轮回收中才被清除.
另外,针对并发标记(还有并发清理)开始后产生的新对象,通常做法是直接全部当成黑色,本轮不会进行清除.这部分对象期间可能也会变成垃圾.这也算是浮动垃圾的一部分.

漏标-读写屏障

漏标会导致被引用的对象被当成垃圾误删除,这是严重bug,必须解决,有以下两种解决方案:

  • 增量更新(Incremental Update):当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次.这可以简化理解为:黑色对象一旦插入了指向白色对象的引用之后,它就变回灰色对象了.
  • 原始快照(Snapshot At The Beginning,SATB):当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,再并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,再重新扫描一次.这样就能扫描到白色的对象,将白色对象直接标记为黑色(目的就是让这种对象再本轮gc清理中能存活下来,待下一轮gc的时候重新扫描,这个对象也有可能是浮动垃圾)

以上无论是对引用关系记录的插入还是删除,虚拟机的记录操作都是通过 写屏障 实现的.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安信可 ESP_01SWIFI模块的使用 (电脑通过usb转tll模块连接wifi模块进行调试)

一:需要用到的模块 (1)安信可的ESP_01wifi模块 ESP-01是深圳安信可科技基于ESP8266芯片开发的串口wifi模块,模组集成了透传功能,即买即用,支持串口指令集,用户通过串口即可实现网络访问…

如何使用JSONB类型在PostgreSQL中存储和查询复杂的数据结构?

文章目录 解决方案1. 创建包含JSONB列的表2. 插入JSONB数据3. 查询JSONB数据4. 创建索引以优化查询性能 示例代码结论 在PostgreSQL中,JSONB是一种二进制格式的JSON数据类型,它允许你在数据库中存储和查询复杂的JSON数据结构。与普通的JSON类型相比&…

【Hadoop】- MapReduce YARN 初体验[9]

目录 提交MapReduce程序至YARN运行 1、提交wordcount示例程序 1.1、先准备words.txt文件上传到hdfs,文件内容如下: 1.2、在hdfs中创建两个文件夹,分别为/input、/output 1.3、将创建好的words.txt文件上传到hdfs中/input 1.4、提交MapR…

量子城域网系列(六):关于量子信道

下图是“墨子号”卫星与兴隆地面站量子密钥分发的实验现场图,是不是很酷。星地高速量子密钥分发是“墨子号”量子卫星的科学目标之一。量子密钥分发实验采用卫星发射量子信号,地面接收的方式,“墨子号”量子卫星过境时,与河北兴隆…

性能监控(本地、服务器)

CPU、内存、磁盘等的监控 一、mac本地性能监控 1. top 终端: top load Avg: 平均负载(1分钟,5 分钟,15 分钟)值不能超过 4,要不然就是超负荷运行 Tasks: 进程数 %Cpu(s): idle :剩余百分比 KiB Mem: free:剩余内存&#xff0…

Mac电池管理软件 Batteries for Mac v2.2.9直装版

Batteries for Mac,作为一款专为Mac用户设计的电池管理软件,以其强大的功能和智能的监测机制,为用户提供了便捷、高效的电池使用体验。 Batteries for Mac(Mac电池)v2.2.9直装版下载 首先,Batteries for Mac具备实时电池监测功能&…

使用Python进行云计算:AWS、Azure、和Google Cloud的比较

👽发现宝藏 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 使用Python进行云计算:AWS、Azure、和Google Cloud的比较 随着云计算的普及&am…

[Kubernetes] etcd的集群基石作用

文章目录 1. 配置存储2. 数据一致性3. 服务发现与协调4. 集群状态中枢5. 集群稳定性 1. 配置存储 etcd作为一个高度可靠的分布式键值存储系统,存储了Kubernetes集群的完整配置和状态数据。集群的元数据,包括节点信息、命名空间、部署、副本集、服务、持…

Modern CSV for Mac:强大的CSV文件编辑器

Modern CSV for Mac是一款功能强大的CSV文件编辑器,专为Mac用户设计,提供直观易用的界面和丰富的功能,使用户能够轻松编辑和管理CSV文件。 Modern CSV for Mac v2.0.6激活版下载 这款软件支持快速导入和导出CSV文件,方便用户与其他…

Java之类和对象

一面向对象的初步认知 1.什么是面向对象 Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想…

【Linux】MySQL的安装及配置(Ubuntu-18.04)

一、安装MySQL 分别安装MySQL服务器、MySQL客户端、C/C开发库 sudo apt-get install mysql-server sudo apt-get install mysql-client sudo apt-get install libmysqlclient-dev 二、配置MySQL 1.查看默认配置文件,此处的user和password为默认提供的,…

强固型工业电脑在码头智能闸口、OCR(箱号识别)、集装箱卡车车载电脑行业应用

集装箱卡车车载电脑应用 背景介绍 针对码头集装箱卡车的调度运用, 结合码头TOS系统设计出了各种平台的车载电脑(VT系列)和车载LED显示屏(VLD系列),同时提供各种安装支架,把车载电脑固定到狭小的驾驶室中;同时提供了各种天线选择(…

【AI开发:音频】二、GPT-SoVITS使用方法和过程中出现的问题(GPU版)

1.FileNotFoundError: [Errno 2] No such file or directory: logs/guanshenxxx/2-name2text-0.txt 这个问题中包含了两个: 第一个:No module named pyopenjtalk 我的电脑出现的就是这个 解决:pip install pyopenjtalk 第二个&#xff1a…

Golang | Leetcode Golang题解之第42题接雨水

题目&#xff1a; 题解: func trap(height []int) (ans int) {n : len(height)if n 0 {return}leftMax : make([]int, n)leftMax[0] height[0]for i : 1; i < n; i {leftMax[i] max(leftMax[i-1], height[i])}rightMax : make([]int, n)rightMax[n-1] height[n-1]for i…

【深度学习】DragGAN

基于StyleGAN的图像拖拽编辑新范式 一、StyleGAN与DragGAN&#xff1a;图像生成与编辑的桥梁二、DragGAN的实现原理三、实例与代码展示四、总结与展望 在深度学习和计算机视觉领域&#xff0c;图像生成和编辑技术一直是研究的热点。StyleGAN作为一种强大的图像生成模型&#xf…

Linux基本命令之正则表达式(转义字符)

一&#xff1a;查看二进制文件 strings 命令&#xff1a;strings 文件名 生成链接文件 ln 命令&#xff1a;ln 选项 源文件(f1) 链接文件&#xff08;f2&#xff09; 软连接&#xff1a;eg:ln -s f1 f2 软链接不能跨分区链接&#xff0c;但可以在同一分区的不同目录下链接…

【python】启动一个公司级项目的完整报错和解决方案

启动一个项目对于新手都是不容易的事情 操作 打开项目 使用pyCharm打开python项目以后&#xff0c;先找main方法&#xff0c;一般在根目录有一个.py的文件 点进去以后会让你配置Python解释器 每个项目都有自己的一个虚拟环境&#xff0c;配置自己的解释器&#xff0c;可能…

【信号处理】基于CNN自编码器的心电信号异常检测识别(tensorflow)

关于 本项目主要实现卷积自编码器对于异常心电ECG信号的检测和识别&#xff0c;属于无监督学习中的生理信号检测的典型方法之一。 工具 方法实现 读取心电信号 normal_df pd.read_csv("/heartbeat/ptbdb_normal.csv").iloc[:, :-1] anomaly_df pd.read_csv(&quo…

MultiHeadAttention在Tensorflow中的实现原理

前言 通过这篇文章&#xff0c;你可以学习到Tensorflow实现MultiHeadAttention的底层原理。 一、MultiHeadAttention的本质内涵 1.Self_Atention机制 MultiHeadAttention是Self_Atention的多头堆嵌&#xff0c;有必要对Self_Atention机制进行一次深入浅出的理解&#xff0c;这…

websocket聊天的功能

第一步 安装相关依赖&#xff1a; node需要安装&#xff1a; npm i socket.io 第二步 前端cdn引入socket 第三步 编写服务端的代码 import http from node:http‘import {Server} from socket.ioconst server http.createServer()const io new Server(server,{cors:true …