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

news2024/10/6 6:47:21

垃圾回收

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

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.coloradmin.cn/o/1693501.html

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

相关文章

SpringCloud的Config配置中心,为什么要分Server服务端和Client客户端?

SpringCloud的Config配置中心,为什么要分Server服务端和Client客户端? 在SpringCloud的Config配置中心中分了Server服务端和Client客户端,为什么需要这样分呢?它的思想是所有微服务的配置文件都放到git远程服务器上,让…

使用FFmpeg推流实现在B站24小时点歌直播

使用FFmpeg推流实现在B站24小时点歌直播 本文首发于个人博客 安装FFmpeg centos7 https://www.myfreax.com/how-to-install-ffmpeg-on-centos-7/ https://linuxize.com/post/how-to-install-ffmpeg-on-centos-7/ 使用FFmpeg在B站直播 https://zhuanlan.zhihu.com/p/2395…

机器学习(五) -- 监督学习(5) -- 线性回归1

系列文章目录及链接 上篇:机器学习(五) -- 监督学习(4) -- 集成学习方法 - 随机森林 下篇:机器学习(五) -- 监督学习(5) -- 线性回归2 前言 tips&#xff1…

Redis教程(十五):Redis的哨兵模式搭建

一、搭建Redis一主二从 分别复制三份Redis工作文件夹,里面内容一致 接着修改7002的配置文件,【redis.windows-service.conf】 port 7002 改成 port 7002 slaveof 127.0.0.1 7001 7003也同样修改 port 7003 slaveof 127.0.0.1 7001 这样就指定了700…

B站滑块登录之极验点选

滑块登录这些东西都不是很难,我个人的去处理的话一般会考虑三种方案,一个是自动化selenium 二是各类打码平台 三是ocr识别,本文是selenium接打码平台,也是个比较常规的操作。 先常规步骤跟着来吧,做登录的话把基本的模…

【启程Golang之旅】运算符与流程控制讲解

欢迎来到Golang的世界!在当今快节奏的软件开发领域,选择一种高效、简洁的编程语言至关重要。而在这方面,Golang(又称Go)无疑是一个备受瞩目的选择。在本文中,带领您探索Golang的世界,一步步地了…

【qt】标准型模型 下

标准型模型 一.前言二.预览数据1.获取表头2.获取数据项 三.保存文件1.文件对话框获取保存文件名2.用文件名初始化文件对象3.打开文件对象4.用文件对象初始化文本流5.写入数据 四.格式1.居右2.居中3.居左4.粗体 五.模型的信号1.解决粗体action问题2.状态栏显示信息 六.总结 一.前…

【Spring Boot】深度复盘在开发搜索引擎项目中重难点的整理,以及遇到的困难和总结

💓 博客主页:从零开始的-CodeNinja之路 ⏩ 收录文章:【Spring Boot】深度复盘在开发搜索引擎项目中重难点的整理,以及遇到的困难和总结 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 什么是搜索引…

NTFS文件系统文件寻址实操记录

前言 最近在学NTFS,发现网上的博客千篇一律,讲的不够通透,于是决定自己写一篇。 本文章通过寻找文件地址这个任务,讲述了NTFS文件系统$Boot文件、$MFT文件的结构,对$MFT文件中的A0、80属性进行了重点分析。 本文对于…

k8s-pod详解

一、Pod基本概念: 1.pod介绍: Pod是kubernetes中最小的资源管理组件,Pod也是最小化运行容器化应用的资源对象。一个Pod代表着集群中运行的一个进程。kubernetes中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的,例如&am…

vs2013使用qt Linguist以及tr不生效问题

一、qt Linguist(语言家)步骤流程 1、创建翻译文件,在qt选项中 2.选择对应所需的语言,得到.ts后缀的翻译文件 3.创建.pro文件,并将.ts配置在.pro文件中 3.使用qt Linguist 打开创建好的以.ts为后缀的翻译文件,按图所示…

python中的条件语句

python中语句的执行顺序 默认情况下,python代码的执行顺序,是从上到下依次执行的,这个顺序是不会变的, python中的条件语句 电脑的CPU芯片是能够进行算术运算也能进行逻辑判断的。 条件语句能够表达“如果...否则...” 这样的语…

P451 try-Catch异常处理

//基本使用演示代码 public static void main(String[] args) { int num1 10; int num2 0; try { int res num1 / num2; }catch (Exception e) { System.out.println(e.getMessage()); } } public class TryCatchDetail { public static void main(String[] args) { //1. 如…

dubbo复习:(8)使用sentinel对服务进行降级

一、下载sentinel-dashboard控制台应用并在8080端口启动 二、项目添加springboot 和dubbo相关依赖(降级规则并未持久化,如果需要持久化,如果需要持久化降级规则,只需增加nacos相关依赖并在nacos中进行配置,然后配置app…

pyside6下没有designer.exe、pyside6-uic.exe等

使用conda安装的pyside6(conda install pyside6),发现pyside6目录下没有designer.exe、pyside6-uic.exe等;designer.exe在Miniconda3/Library/bin下 pyside6-uic.exe、pyside6-rcc.exe在Miniconda3\Scripts下 但是 使用pip安装…

前端nvm、nodejs、npm、cnpm、yarn安装教程(超详细图文,含卸载旧的nodejs,安装及环境变量配置)

最近换了新电脑,一开始在网上找了一个教程让下载nvm-noinstall.zip 压缩包解压使用,踩坑了,过程复杂最后报错无法用。 后来搜到下文教程,直接使用nvm。exe进行安装,方便快捷。下面这个文章写的很详细,从如何…

Spark搭建 Standalone模式详细步骤

Standalone模式概述: Standalone模式是Spark自带的一种集群模式(本地集群,不依赖与外部集群,比如Yarn),可以真实地在多个机器之间搭建Spark集群的环境。 Standalone是完整的Spark运行环境,其中: Master角…

失业潮中如何突围?优秀PPT案例助你职场逆袭

在这个变幻莫测的时代,失业潮像一场突如其来的暴风雨,许多人在职场的大海中迷失方向。但别担心,即使风浪再大,总有勇敢的航海者能够乘风破浪,找到属于自己的那片新大陆。 今天,我们就来聊聊,在…

leecode 1206|跳表的设计

跳表 跳表,一种链表数据结构,其增删改茶的效率能和平衡树相媲美 leecode1206 可以看上面的那个动画,动画效果很贴切。 我简单讲讲它的机制吧,每个节点不单单是一个,测试好几层,然后同一层的节点和统一节点…

软件杯 深度学习验证码识别 - 机器视觉 python opencv

文章目录 0 前言1 项目简介2 验证码识别步骤2.1 灰度处理&二值化2.2 去除边框2.3 图像降噪2.4 字符切割2.5 识别 3 基于tensorflow的验证码识别3.1 数据集3.2 基于tf的神经网络训练代码 4 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 &#x…