【Go专家编程——内存管理——垃圾回收】

垃圾回收

所谓的垃圾就上不在需要的内存块,垃圾如果不清理,这些内存块就没有办法再次被分配使用。在不支持垃圾回收的编程语言中,这些垃圾内存就上泄露的内存。

1. 垃圾回收算法

常见的垃圾回收算法有3种

  • 引用计数:对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0时回收该对象
    • 优点:对象可以很快被回收,不会出现内存耗尽或达到某个阈值时才回收
    • 缺点:不能很好地处理循环引用,实施维护引用计数也有一定的代价
    • 代表语言:Python,PHP,Swift
  • 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记为"被引用",没有标记的对象被回收
    • 优点:解决了引用计数的缺点
    • 缺点:需要STW,即暂停程序运行
    • 代表语言:Go(三色标记法)
  • 分代收集:按照对象声明周期的长短划分不同的代空间,生命周期长的放入老年代,短的放入新生代,不同代有不同的回收算法和回收频率
    • 优点:回收性能好
    • 缺点:算法复杂
    • 代表语言:Java

2.Go垃圾回收

2.1 垃圾回收的原理

垃圾回收的核心就是标记处那些内存还在使用,哪些内存不再使用了(即未被引用),把未被引用的内存回收,以供后续内存分配使用。

垃圾回收开始时从root对象扫描,把root对象引用的内存标记为“被引用”,考虑到内存块中存放的可能是指针,所以还需要递归地进行标记,全部标记完成后,只保留被标记的内存,未被标记的内存全部标记为未分配即完成了回收。

2.2 内存标记(Mark)

之前的博客有介绍了span数据结构,span中维护了一个个内存块,并有成员变量allocBits表示每个内存块的分配情况。在span的数据结构中还有另一个位图gcmarkBits(之前的文章中未被写出),用于标记内存块被引用的情况。

allocBits和gcmarkBits的数据结构完全一样,标记结束后就上内存回收,回收时将allocBits指向gcmarkBits,代表标记过的内存才是存活的内存,gcmarkBits则会在下次标记时重新分配内存。

2.3 三色标记法

三色对应了垃圾回收过程中对象的三种状态

  • 灰色:对象还在标记队列中等待
  • 黑色:对象已被标记,gcmarkBits对应的位为1(该对象不会再本次GC中被清理)
  • 白色:对象未被标记,gcmarkBits对应的位为0(该对象会在本次GC中被清理)

在这里插入图片描述

  1. 初始化阶段:
    • 所有对象最初都被标记为白色,表示尚未访问。
    • 设置一个根集,根集通常包括当前的栈变量、全局变量以及Go运行时的数据结构等可以直接访问到的对象。这些根集中的对象被标记为灰色。
  2. 并发标记阶段:
    • 从灰色对象开始,垃圾回收器会遍历这些对象引用的所有对象,并将其从白色改为灰色,表示这些对象已被发现但其引用的对象还未被检查。
    • 同时,标记过程会递归进行,每当完成一个对象的引用检查(即将其引用的所有白色对象标记为灰色),该对象就会被标记为黑色,表示该对象及其所有引用链上的可达对象都已被访问过,不会再被重新访问。
    • 这个过程是并发执行的,即垃圾回收器与程序的其他部分并行工作,以减少停顿时间。
  3. 重新扫描(重新标记)阶段:
    • 由于标记阶段是并发进行的,程序可能在此期间修改了某些对象的引用关系,这可能导致一些本应标记为灰色或黑色的对象仍保持为白色。因此,需要有一个阶段来修正这种不一致,这个阶段称为重新扫描或重新标记阶段。
    • 在这个阶段,垃圾回收器会暂停所有非垃圾回收相关的任务,再次检查灰色对象,并确保它们的引用关系已经被正确处理,新发现的白色对象会被标记为灰色继续处理,直至没有灰色对象剩余。
  4. 清理阶段:
    • 当所有可达对象都被标记为黑色后,垃圾回收器知道所有白色对象都是不可达的,可以被安全地回收。
    • 这个阶段会释放那些白色对象占用的内存空间,为新的分配做准备。

STW(Stop Whe World)就是停止所有的goroutine,专心做垃圾回收,待垃圾回收结束后再回复goroutine
STW时间的长短直接影响了应用的执行。

3. 垃圾回收优化

为了缩短STW的时间,Go也在不断地优化垃圾回收算法。

3.1 写屏障(Write Barrier)

  • 写屏障就是让goroutine与GC同时运行的手段,写屏障可以打打缩短STW的时间。
  • 写屏障类似一种开关,在GC的特定时机开启,开启后指针传递时会标记指针,即本轮不回收,下次GC时再确定。
  • GC过程中新分配的内存会被立即标记,用的正是写屏障技术,即GC过程中分配的内存不会再本轮GC中回收

3.2 辅助GC(Mutator Assist)

为了防止内存分配过快,在GC执行过程中,如果goroutine需要分配内存,那么该goroutine会参与一部分GC的工作,即帮组GC做一部分工作,这个机制叫做Mutator Assist。

4. 垃圾回收的触发时机

4.1 内存分配量达到阈值触发GC

每次内存分配时都会检查当前内存分配量是否已达到阈值,如果达到阈值则立即启动GC。
阈值 = 上次GC内存分配量 * 内存增长率
内存增长率由环境变量GOGC控制,默认为100,即每当内存扩大一倍时启动GC

4.2 定期触发GC

默认情况下,最长2分钟触发一次GC。
通过变量forcegcperiod变量中被声明

4.3 手动触发

程序代码中也可以使用使用runtime.GC()来手动触发GC,主要用于GC的性能测试和统计。

5. GC性能优化

  • GC性能与对象数量负相关,对象越多GC性能越差,对程序影响越大。
  • 所以GC性能优化的思路之一就是减少对象分配的个数:比如使用对象复用或使用大对象组合多个小对象
  • 内存逃逸现象会产生一些隐式的内存分配,也有可能成为GC的负担

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

yolov10 快速使用及训练

参考: https://docs.ultralytics.com/models/yolov10/ ultralytics其实大多数系列都能加载使用: 官方: https://github.com/THU-MIG/yolov10.git 代码参考: https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/train-yolov10-object-…

一篇文章讲透排序算法之希尔排序

希尔排序是对插入排序的优化,如果你不了解插入排序的话,可以先阅读这篇文章:插入排序 目录 1.插入排序的问题 2.希尔排序的思路 3.希尔排序的实现 4.希尔排序的优化 5.希尔排序的时间复杂度 1.插入排序的问题 如果用插入排序对一个逆序…

521源码-免费代码基础学习-PHP如何运用变量教程

更多网站源码学习教程,请点击👉-521源码-👈获取最新资源 为什么要学习PHP?“我可以用JavaScript来实现程序编写。”但JavaScript的能力是有限的,JavaScript通常运行在浏览器(客户端)&#xff0…

go语言中for的4种循环形式总结

和其他语言不一样,go语言中的循环语句只有for一种,但是go里面的for却有3种不同的循环形式,总结如下: 1. 无限循环 for { //这个就是一个“死循环”,注意必须要有 break条件,否则就真成死循环了 } 2. fo…

Redis 源码学习记录:集合 (set)

无序集合 Redis 源码版本:Redis-6.0.9,本篇文章无序集合的代码均在 intset.h / intset.c 文件中。 Redis 通常使用字典结构保存用户集合数据,字典键存储集合元素,字典值为空。如果一个集合全是整数,则使用字典国语浪费…

PostgreSQL入门教程

PostgreSQL是一种开源的关系型数据库管理系统,它具有高度的可靠性、可扩展性和性能。下面是一个简单的PostgreSQL入门教程,帮助你开始使用这个强大的数据库管理系统。 步骤1:安装PostgreSQL 首先,你需要下载并安装PostgreSQL。你…

2024年最全的信息安全、数据安全、网络安全标准分享(可下载)

以上是资料简介和目录,如需下载,请前往星球获取:https://t.zsxq.com/Gz1a0

【全网最全】2024电工杯数学建模A题成品论文+前三题完整解答matlab+py代码等(后续会更新成品论文)

您的点赞收藏是我继续更新的最大动力! 一定要点击如下的卡片链接,那是获取资料的入口! 【全网最全】2024电工杯数学建模A题成品论文前三题完整解答matlabpy代码等(后续会更新成品论文)「首先来看看目前已有的资料&am…

Python 点云平面分割【RANSAC算法】

点云平面分割 一、介绍1.1 概念1.2 算法思路1.3 参数设置二、代码示例三、结果示例其他参考链接:C++中实现点云平面分割 一、介绍 1.1 概念 点云平面分割:可以在点云数据中找到平面并计算平面模型系数,同时输出平面点云及非平面点云。 1.2 算法思路 实现思路: 首先,采用…

Sass是什么?有哪些优缺点?

目录 一、Sass是什么? 二、Sass的优缺点 三、Sass与SaaS 一、Sass是什么? Sass是世界上最成熟、最稳定、最强大的专业级CSS扩展语言。 Sass makes CSS fun again. Sass is an extension of CSS, adding nested rules, variables, mixins, selector in…

【C++高阶(一)】继承

目录 一、继承的概念 1.继承的基本概念 2.继承的定义和语法 3.继承基类成员访问方式的变化 ​编辑 4.总结 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 1.派生类中的默认构造函数 2.派生类中的拷贝构造函数 3.派生类中的移动构造函数…

英语学习笔记25——Mrs. Smith‘s kitchen

Mrs. Smith’s kitchen 史密斯太太的厨房 词汇 Vocabulary Mrs. 夫人【已婚】 复习:Mr. 先生 全名 / 姓    Mrs. 夫人 全名 / 丈夫的姓    Miss 小姐(未婚) 全名 / 姓    Ms. 女士 全名 / 姓 查看婚姻状况,可以观察…

springboot项目中图片上传之后需要重启工程才能看到图片?

需求背景 最近在做一个用户自定义上传头像的小需求,用户上传头像然后需要立马回显。 需求是很常见的、正当的需求。如果不使用到对象存储这类服务,我们把用户头像的图片文件仅存在本地就可以了。我们在开发的过程中为了工程管理方便通常下意识会将图片…

freertos串口DMA队列发送卡死

调试回调函数的时候,我在cube中删除了默认的DMA通道,又新增了另外一个通道,导致NVIC中,该通道的优先级为0,后来改成了5就正常了。

Modbus TCP转Profinet网关测试配置案例

本案例采用XD-ETHPN20网关做为Modbus TCP通信协议设备与Profinet通信协议设备连接的桥梁。Modbus TCP是一种基于TCP/IP协议的工业通信协议,而Profinet则是用于太网通信的协议。Modbus TCP转Profinet网关可实现这两种不同协议之间的数据交换和传输,极大地…

算法刷题笔记 逆序对的数量(C++实现)

文章目录 题目描述解题代码&#xff08;蛮力版&#xff09;解题代码&#xff08;基于归并排序&#xff09; 题目描述 给定一个长度为n的整数数列&#xff0c;请你计算数列中的逆序对的数量。逆序对的定义如下&#xff1a;对于数列的第i个和第j个元素&#xff0c;如果满足i<…

Python高级进阶--dict字典

dict字典⭐⭐ 1. 字典简介 dictionary&#xff08;字典&#xff09; 是 除列表以外 Python 之中 最灵活 的数据类型&#xff0c;类型为dict 字典同样可以用来存储多个数据字典使用键值对存储数据 2. 字典的定义 字典用{}定义键值对之间使用,分隔键和值之间使用:分隔 d {中…

【ECharts】数据可视化

目录 ECharts介绍ECharts 特点Vue2使用EChats步骤安装 ECharts引入 ECharts创建图表容器初始化图表更新图表 示例基本柱状图后台代码vue2代码配置 组件代码运行效果 基本折线图示例代码组件 基础饼图示例代码后台前端配置组件运行效果 其他 ECharts介绍 ECharts 是一个由百度开…

spring模块(一)容器(4)ApplicationContextAware

一、介绍 1、问题引入 为了获取已被实例化的Bean对象,如果使用再次加载配置文件的方法,可能会出现一个问题,如一些线程配置任务, 会启动两份,产生了冗余. ApplicationContext appContext new ClassPathXmlApplicationContext("applicationContext.xml"); UserS…

python 多线程处理图片

thread for i in range(len(ori_path)):for filename in os.listdir(ori_path[i]):number_img number_img 1print("正在处理第" str(number_img) "张图片")img_name ori_path[i] filenamet Thread(target deal_one_img, args [img_name, filenam…