Go语言垃圾回收GC(完整)

news2025/6/19 22:34:12

垃圾回收的概念

GC(垃圾回收)是 Go 语言中的一个重要机制,用于自动管理内存
在 Go 语言中,GC 会自动发现和回收那些不再被使用的内存空间,从而防止内存泄漏和有
效利用内存。

内存垃圾怎样产生

  • 程序在内存上被分为堆区、栈区、全局数据区、代码段、数据区五个部分。
  • 对于某些早期的编程语言栈上的内存由编译器管理回收,堆上的内存空间需要程序员负责申请与释放。
  • Go中的栈上内存仍由编译器负责管理回收,而堆上的内存由编译器和垃圾收集器负责管理回收。
  • 垃圾是指程序向堆栈申请的内存空间,随着程序的运行已经不再使用这些内存空间,这时如果不释放他们就会造成垃圾也就是内存泄漏。

GC 的工作原理

 GC的核心思想是自动找到那些不再被引用的内存块,然后将其释放。Go 语言使用的是增强型标记-清除算法。简单来说,这个算法会先遍历所有活跃的变量并进行标记,然后清除未被标记的变量(不可达对象)。不过,Go的GC经过多次优化,能够在程序运行的同时有效地完成这些任务,从而减少对程序性能的影响。

GC 的优势

  • 自动化内存管理:我们不需要手动释放内存,减少了内存错误的几率
  • 提升开发效率:可以更专注于业务逻辑的开发,而不用担心内存管理,
  • 安全性高:通过自动管理内存,避免了内存泄漏和悬空指针等问题。

GC 的影响与优化

尽管 GC 提高了内存管理的便利性,但是也会有一定的性能开销,可以优化

  • 减少内存分配:尽量重用对象,避免频繁的内存分配和释放;
  • 合并小对象:减少小对象的分配数量,通过合并提升内存使用效率:
  • 调整 GC 触发阈值:根据程序的具体需求,调整 GC 的触发阈值,从而优化性能

手动内存管理

虽然 Go 语言中的 GC机制非常优秀,但在一些极端情况下,手动管理内存仍然是必要的。这包括使用 sync.Pool 等工具来管理对象池,减少 GC 触发的频率。

go的GC版本迭代

V1.3以前:STW

go runtime在一定条件下(内存超过阈值或定期如2min),暂停所有任务的执行,进行mark(标记)和sweep(清扫)操作,操作完成后启动所有任务的执行。在内存使用较多的场景下,go程序在进行垃圾回收时会发生非常明显的卡顿现象。

V1.3:mark STW & sweep(标记清除法)

1.3版本中,go runtime分离了mark和sweep操作,和以前⼀样,也是先暂停所有任务执⾏并启动
mark,mark完成后⻢上就重新启动被暂停的任务了,⽽是让sweep任务和普通协程任务⼀样并⾏的和其他任务⼀起执⾏。

v1.5:三⾊标记

三色抽象和垃圾回收

  • 白色对象:未被标记的对象,这些对象可能会在垃圾回收的过程中被回收。
  • 灰色对象:已被标记为活跃但其引用对象尚未完全扫描的对象。
  • 黑色对象:活跃且其所有引用对象都已经标记完毕,不会被回收。
go1.5正在实现的垃圾回收器“⾮分代的、⾮移动的、并发的、三⾊的标记清除垃圾收集器”。这种⽅法的mark操作可以渐进执⾏的⽽不需每次都扫描整个内存空间,可以减少stop the world的时间。

1.8:混合写屏障

由于标记操作和⽤⼾逻辑是并发执⾏的,⽤⼾逻辑会时常⽣成对象或者改变对象的引⽤。例如把⼀个对象标记为⽩⾊准备回收时,⽤⼾逻辑突然引⽤了它,或者⼜创建了新的对象。由于对象初始时都看为⽩⾊,会被 GC 回收掉。
GC 对扫描过后的对象使⽤操作系统写屏障功能来监控这段内存。如果这段内存发⽣引⽤改变,写屏障会给垃圾回收期发送⼀个信号,垃圾回收器捕获到信号后就知道这个对象发⽣改变,然后重新扫描这个对象,看看它的引⽤或者被引⽤是否改变。利⽤状态的重置实现当对象状态发⽣改变的时候,依然可以再次其引⽤的对象。

用下面这个例子解释并发带来的问题,当从A这个GC root找到引用对象B时,B变灰A变黑。这时用户goroutine执行把A到B的引用改成了A到C的引用,同时B不再引用C。然后GC goroutine又执行,发现B没有引用对象,B变黑。而这时由于A已经变黑完成了扫描,C将当做白色不可达对象被清除。

解决办法:引入写屏障。当发现A已经标记为黑色了,若A又引用C,那么把C变灰入队。这个write_barrier是编译器在每一处内存写操作前生成一小段代码来做的。

// 写屏障伪代码
write_barrier(obj,field,newobj){
    if(newobj.mark == FALSE){
        newobj.mark = TRUE
        push(newobj,$mark_stack)
    }
    *field = newobj
}

如何非递归的实现遍历mark可达节点,显然需要一个队列。

这个队列也帮助区分黑色对象和灰色对象,因为标记位只有一个。标记并且在队列中的是灰色对象,标记了但是不在队列中的黑色对象,末标记的是白色对象。

root node queue
while(queue is not nil) {
  dequeue // 节点出队
  process // 处理当前节点 
  child node queue // 子节点入队
}

垃圾回收三⾊标记法实现原理

  1. 所有对象初始都被标记为⽩⾊,表⽰这些对象尚未被扫描过。
  2.  从根对象开始(如全局变量、栈中的变量等),将其引⽤的对象标记为灰⾊,表⽰这些对象已经被 扫描过,但其引⽤的对象还未扫描。
  3. 继续对灰⾊对象进⾏扫描,将其引⽤的对象标记为灰⾊,并将当前灰⾊对象标记为⿊⾊,表⽰这些 对象已经被扫描过,其引⽤的对象也已被扫描过。
  4. 遍历所有⽩⾊对象,将其标记为死亡对象,进⾏垃圾回收。

垃圾回收的实现

Go采用“并发标记清除”来管理和回收不再使用的内存。

流程:

  1. 标记阶段:垃圾回收器从根对象(如全局变量、栈上的指针等)开始,通过遍历对象图的方式标记所有可达的对象。这个过程是并发进行的,与程序的执行同时进行,不会阻塞程序的运行。
  2. 并发标记阶段:在标记阶段的同时,Go语言的垃圾回收器还会与程序的执行并发的标记新创建的对象,这个过程通过与程序的执行并行运行,以减少程序性能的影响。
  3. 清除阶段:在标记阶段完成后,垃圾回收器会对堆中未标记对象进行清除。这个过程会暂停程序的执行,因为它需要遍历整个堆并回收未标记的对象。清除后的内存空间会被重新分配给新的对象使用。
  4. 并发清除阶段:在清除阶段完成之后,go语言的垃圾回收器会继续与程序的执行同时进行,以减少对程序性能的影响。

插⼊,删除,混合写屏障

屏障
Go 语⾔的屏障(Barrier)是⼀种同步机制,⽤于协调多个 Goroutine 的执⾏。在 Go 语⾔中,屏障通常⽤于等待⼀组 Goroutine 完成⼀定的任务,然后再继续执⾏下⼀步操作。
作⽤
Go 语⾔的屏障机制可以帮助开发者协调多个 Goroutine 的执⾏,避免出现竞争条件和死锁等问题,提⾼程序的可靠性和性能。
插⼊屏障
插⼊屏障(Barrier Insertion)是⼀种⽤于控制 Goroutine 之间交互的同步机制。在 Go 语言的垃圾回收器中,写屏障通过在每次写操作时,插入额外的代码来工作,具体来说,每次 Go 程序写操作(比如赋值语句)进行时,都会调用一个写屏障函数。对于标记-清除算法,写屏障会在新引用插入对象时,将该引用的对象标记为灰色。这种做法确保黑色对象不会直接指向白色对象,并且所有新的引用都会被回收器追踪。
删除屏障
删除屏障通(Barrier Elimination)常⽤于⼀些简单的同步操作,例如读写锁和互斥锁
等,当这些锁被频繁地获取和释放时,会产⽣较⼤的开销。在这种情况下,删除屏障可以通过使⽤
⼀些优化技术,例如锁消除和锁粗化,来避免不必要的同步操作,从⽽提⾼程序的性能。
混合写屏障
混合写屏障(Mixed-Mode Barrier)是 Go 语⾔中常⽤的同步机制之⼀,可以根据具体的需求和场景选择不同的屏障实现,从⽽更加灵活地协调多个 Goroutine 之间的交互,确保程序的正确性和可靠性。

GO语⾔什么时间会触发垃圾回收,如何调优?

Go 语言的 GC 触发机制主要是基于两种策略

  1.  内存分配量:当已分配的内存量达到了某个阈值时,GC 会被触发。这个阈值是基于已分配内存量和内存增长速率动态调整的。 
  2. 时间间隔:如果内存分配量没有达到触发 GC 的阈值,经过一段时间(默认2分钟)后,GC 会被触发以确保垃圾及时回收。

Go语⾔的垃圾回收器是⼀种⾃动内存管理机制,⽤于回收不再使⽤的内存。有以下三种情况

  1. 定时触发:默认是垃圾回收器会在每个堆分配周期后触发,堆分配周期由 GOGC 环境变量指 定,默认值为100。
  2. 内存分配触发:当程序进⾏内存分配时,如果当前可⽤内存不⾜,垃圾回收器会被触发,以回收不再使⽤的内存,并将其加⼊内存池中供后续使⽤。
  3. ⼿动触发:程序可以通过调⽤ runtime.GC() 函数⼿动触发垃圾回收器,以回收不再使⽤的内 存。

调优

  •  调整GOGC环境变量的值:垃圾回收器触发时间默认为100,如果内存使⽤量⼩,可以将其调⼤⼀些设置成200、300.
  •  减少内存分配:可以通过使⽤对象池、复⽤对象等技术来减少内存分配。
  • 避免⼤对象:⼤对象会占⽤⼤内存。
  •  使⽤指针:值类型相⽐于指针类型,值类型会被复制,增加内存。
  • 调整堆的⼤⼩
  • 分析GC⽇志

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

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

相关文章

黑马头条vue2.0项目实战(一)——项目初始化

1. 图标素材(iconfont简介) 制作字体图标的工具有很多,推荐使用:iconfont-阿里巴巴矢量图标库。 注册账户 创建项目 可以根据项目自定义 class 前缀 上传图标到项目 生成链接,复制 css 代码,在项目中使用…

数组与链表谁访问更快

一、线性表 线性表是数据结构中的一种基本类型,它由一组线性排列的元素组成。线性表的特点是可以进行顺序访问,但不支持随机访问。 二、非线性表 非线性表是数据结构中另一种类型,如树和图,它们由多个节点组成,节点…

【云原生】Docker搭建知识库文档协作平台Confluence

目录 一、前言 二、企业级知识库文档工具部署形式 2.1 开源工具平台 2.1.1 开源工具优点 2.1.2 开源工具缺点 2.2 私有化部署 2.3 混合部署 三、如何选择合适的知识库平台工具 3.1 明确目标和需求 3.2 选择合适的知识库平台工具 四、Confluence介绍 4.2 confluence特…

链表篇: 01-从尾到头打印链表

解题思路: 直接往数组中加入数据,然后通过Java提供的工具类(coollections) 直接进行数组的反转。 代码实现: import java.util.*; /** * //ListNode 的数据结构 * * public class ListNode { * int val; * ListNode next null; * * …

韩顺平0基础学java——第39天

p820-841 jdbc和连接池 1.JDBC为访问不同的数据库提供了统一的接口,为使用者屏蔽了细节问题。 2.Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。 3.jdbc原理图 JDBC带来的好处 2.JDBC带来的…

10 Vue 特性要点

Vue2 特性要点 Vue2 源码理解 Vue 双向数据绑定 先从单向绑定切入单向绑定非常简单,就是把Mode1绑定到view,当我们用Javascript代码更新Model时, view就会自动更新 双向绑定就很容易联想到了,在单向绑定的基础上,用户更新了View, Mode1的数据也自动被更新了 因为 Vue 是数据双向…

手把手教你集成GraphRag.Net:打造智能图谱搜索系统

在人工智能和大数据发展的背景下,我们常常需要在项目中实现知识图谱的应用,以便快速、准确地检索和使用信息。 今天,我将向大家详细介绍如何在一个新的.NET项目中集成GraphRag.Net,这是一个参考GraphRag实现的.NET版本&#xff0c…

Flutter——全网最精致木鱼APP可上架应用市场

研发背景 工作之余,闲来无事,想着研发一款用户可能会经常用到的一款APP,并且能够顺便掌握一下Flutter Material Design 3 UI,所以就有了这款比较精致的木鱼APP的诞生。 开源代码 https://github.com/z244370114/woodenfish

YOLOV8源码解读-C2f模块-以及总结c2模块、Bottleneck

c2f模块是对c2模块的改进 c2模块图解解读 先给出YOLOV8中卷积的定义模块一键三连-卷积-BN-激活函数 def autopad(k, pNone, d1): # kernel, padding, dilation"""Pad to same shape outputs."""if d > 1:k d * (k - 1) 1 if isinstance…

linux练习2

一、搭建nfs服务器,客户端可从服务端/share目录上传与下载文件 **服务端** 1、下载相关安装包 [rootserver ~]# yum install rpcbind -y [rootserver ~]# yum install nfs-utils -y 2、 创建共享文件夹/share并授予权限 [rootserver ~]# mkdir /share [rootserv…

结构体笔记

结构体 C语言中的数据类型: 基本数据类型:char/int/short/double/float/long 构造数据类型:数组,指针,结构体,共用体,枚举 概念: 结构体是用户自定义的一种数据类型&#xff0c…

【七】Hadoop3.3.4基于ubuntu24的分布式集群安装

文章目录 1. 下载和准备工作1.1 安装包下载1.2 前提条件 2. 安装过程STEP 1: 解压并配置Hadoop选择环境变量添加位置的原则检查环境变量是否生效 STEP 2: 配置Hadoop2.1. 修改core-site.xml2.2. 修改hdfs-site.xml2.3. 修改mapred-site.xml2.4. 修改yarn-site.xml2.5. 修改hado…

全球相机控制面板市场展望与未来增长机遇:预计未来六年年复合增长率CAGR为4.3%

在全球摄影器材和专业影像设备需求增长的背景下,相机控制面板正成为市场的焦点。本文详细分析了全球相机控制面板市场的现状、增长趋势及未来前景,旨在为投资者和业内人士提供深入的市场洞察和指导。 市场概览 据恒州诚思团队研究分析显示,2…

Linux内核 mmap内存映射的实现原理

在Linux内核以及Linux系统编程的时候,经常会碰到mmap内存映射,mmap函数是实现高性能编程的一个关键点。本文详细介绍一下mmap实现原理。 虚拟地址映射物理地址 虚拟地址映射物理地址采用的是页表机制,64位CPU采用的是4级页表。 64位CPU虚拟…

算法板子:堆排序——找出数组中前m个最小元素,包括构造小根堆、查询堆中最小值

基础知识: 堆是一棵完全二叉树,除了最后一层外每一层都是满的,并且最后一层如果有右节点必有左节点堆的节点从1开始编号; 如果一个节点的编号是i,那么该节点的左孩子是2i,右孩子是2i1小根堆中,父节点的值小…

医院影像平台源码,C/S体系结构的C#语言PACS系统全套商业源代码

医学学影像临床信息系统具有图像采集、显示、存储、传输和管理等功能,支持DICOM影像设备和非DICOM影像设备,可以识别CT、MR、CR/DR、X光、DSA、B超、NM、SC等设备的图像类型,可对数字影像进行无损压缩和有损压缩处理。C/S体系结构的多媒体数据…

B端系统UI个性化设计:感受定制之美

B端系统UI个性化设计:感受定制之美 引言 艾斯视觉作为ui设计和前端开发从业者,其观点始终认为:在当今竞争激烈的商业环境中,B端(Business-to-Business)系统的设计不再仅仅是功能性的堆砌,而是…

Hakuin:一款自动化SQL盲注(BSQLI)安全检测工具

关于Hakuin Hakuin是一款功能强大的SQL盲注漏洞安全检测工具,该工具专门针对BSQLi设计,可以帮助广大研究人员优化BSQLi测试用例,并以自动化的形式完成针对目标Web应用程序的漏洞扫描与检测任务。 该工具允许用户以轻松高效的形式对目标Web应…

Python | TypeError: ‘function’ object is not subscriptable

Python | TypeError: ‘function’ object is not subscriptable 在Python编程中,遇到“TypeError: ‘function’ object is not subscriptable”这一错误通常意味着你尝试像访问列表、元组、字典或字符串等可订阅(subscriptable)对象那样去…

短视频矩阵源码技术分享

在当今数字媒体时代,短视频已成为吸引观众和传递信息的重要手段。对于开发者而言,掌握短视频矩阵源码技术不仅是提升自身技能的需要,更是把握行业发展趋势的必然选择。本文将深入探讨短视频矩阵源码的关键技术要点及其实现方法,帮…