GO GC 垃圾回收机制

Go语言GC机制超详细 什么是GC?他的英文全称(英语:Garbage Collection,缩写为GC),在计算机科学中是一种自动的存储器管理机制。当一个计算机上的动态存储器不再需要时,就应该予以释放,以让出存储器,这种存储器资源管理,称为垃圾回收。垃圾回收器可以让程序员减轻许多负担,也减少程序员犯错的机会(-----来自维基百科)简单地说,垃圾回收(GC)是在后台运行一个守护线程,它的作用是在监控各个对象的状态,识别并且丢弃不再使用的对象来释放和重用资源。 阅读详情

原文链接:https://segmentfault.com/a/1190000018161588
垃圾回收(Garbage Collection,简称GC)是编程语言中提供的内存管理功能。

在传统的系统级编程语言(主要指C/C++)中,程序员定义了一个变量,就是在内存中开辟了一段相应的空间来存值。由于内存是有限的,所以当程序不再需要使用某个变量的时候,就需要销毁该对象并释放其所占用的内存资源,好重新利用这段空间。在C/C++中,释放无用变量内存空间的事情需要由程序员自己来处理。就是说当程序员认为变量没用了,就手动地释放其占用的内存。但是这样显然非常繁琐,如果有所遗漏,就可能造成资源浪费甚至内存泄露。当软件系统比较复杂,变量多的时候程序员往往就忘记释放内存或者在不该释放的时候释放内存了。这对于程序开发人员是一个比较头痛的问题。

为了解决这个问题,后来开发出来的几乎所有新语言(java,python,php等等)都引入了语言层面的自动内存管理 – 也就是语言的使用者只用关注内存的申请而不必关心内存的释放,内存释放由虚拟机(virtual machine)或运行时(runtime)来自动进行管理。而这种对不再使用的内存资源进行自动回收的功能就被称为垃圾回收。

垃圾回收常见的方法
引用计数(reference counting)

引用计数通过在对象上增加自己被引用的次数,被其他对象引用时加1,引用自己的对象被回收时减1,引用数为0的对象即为可以被回收的对象。这种算法在内存比较紧张和实时性比较高的系统中使用的比较广泛,如ios cocoa框架,php,python等。

优点:

1、方式简单,回收速度快。

缺点:

1、需要额外的空间存放计数。

2、无法处理循环引用(如a.b=b;b.a=a这种情况)。

3、频繁更新引用计数降低了性能。

标记-清除(mark and sweep)

该方法分为两步,标记从根变量开始迭代得遍历所有被引用的对象,对能够通过应用遍历访问到的对象都进行标记为“被引用”;标记完成后进行清除操作,对没有标记过的内存进行回收(回收同时可能伴有碎片整理操作)。这种方法解决了引用计数的不足,但是也有比较明显的问题:每次启动垃圾回收都会暂停当前所有的正常代码执行,回收是系统响应能力大大降低!当然后续也出现了很多mark&sweep算法的变种(如三色标记法)优化了这个问题。

复制收集

复制收集的方式只需要对对象进行一次扫描。准备一个「新的空间」,从根开始,对对象进行扫,如果存在对这个对象的引用,就把它复制到「新空间中」。一次扫描结束之后,所有存在于「新空间」的对象就是所有的非垃圾对象。

这两种方式各有千秋,标记清除的方式节省内存但是两次扫描需要更多的时间,对于垃圾比例较小的情况占优势。复制收集更快速但是需要额外开辟一块用来复制的内存,对垃圾比例较大的情况占优势。特别的,复制收集有「局部性」的优点。

在复制收集的过程中,会按照对象被引用的顺序将对象复制到新空间中。于是,关系较近的对象被放在距离较近的内存空间的可能性会提高,这叫做局部性。局部性高的情况下,内存缓存会更有效地运作,程序的性能会提高。

对于标记清除,有一种标记-压缩算法的衍生算法:

对于压缩阶段,它的工作就是移动所有的可达对象到堆内存的同一个区域中,使他们紧凑的排列在一起,从而将所有非可达对象释放出来的空闲内存都集中在一起,通过这样的方式来达到减少内存碎片的目的。

分代收集(generation)

这种收集方式用了程序的一种特性:大部分对象会从产生开始在很短的时间内变成垃圾,而存在的很长时间的对象往往都有较长的生命周期。

根据对象的存活周期不同将内存划分为新生代和老年代,存活周期短的为新生代,存活周期长的为老年代。这样就可以根据每块内存的特点采用最适当的收集算法。

新创建的对象存放在称为 新生代(young generation)中(一般来说,新生代的大小会比 老年代小很多)。高频对新生成的对象进行回收,称为「小回收」,低频对所有对象回收,称为「大回收」。每一次「小回收」过后,就把存活下来的对象归为老年代,「小回收」的时候,遇到老年代直接跳过。大多数分代回收算法都采用的「复制收集」方法,因为小回收中垃圾的比例较大。

这种方式存在一个问题:如果在某个新生代的对象中,存在「老生代」的对象对它的引用,它就不是垃圾了,那么怎么制止「小回收」对其回收呢?这里用到了一中叫做写屏障的方式。

程序对所有涉及修改对象内容的地方进行保护,被称为「写屏障」(Write Barrier)。写屏障不仅用于分代收集,也用于其他GC算法中。

在此算法的表现是,用一个记录集来记录从新生代到老生代的引用。如果有两个对象A和B,当对A的对象内容进行修改并加入B的引用时,如果①A是「老生代」②B是「新生代」。则将这个引用加入到记录集中。「小回收」的时候,因为记录集中有对B的引用,所以B不再是垃圾。

以上收集方法在Java的GC中是目前主要的收集分类,但是go为了性能提升又升级了新的收集方法

三色标记算法
三色标记算法是对标记阶段的改进,原理如下:

起初所有对象都是白色。
从根出发扫描所有可达对象,标记为灰色,放入待处理队列。
从队列取出灰色对象,将其引用对象标记为灰色放入队列,自身标记为黑色。
重复 3,直到灰色对象队列为空。此时白色对象即为垃圾,进行回收。
可视化如下。
在这里插入图片描述

三色标记的一个明显好处是能够让用户程序和 mark 并发的进行,具体可以参考论文:《On-the-fly garbage collection: an exercise in cooperation.》。Golang 的 GC 实现也是基于这篇论文,后面再具体说明。

GO的垃圾回收器
go语言垃圾回收总体采用的是经典的mark and sweep算法。

v1.3以前版本 STW(Stop The World)
golang的垃圾回收算法都非常简陋,然后其性能也广被诟病:go runtime在一定条件下(内存超过阈值或定期如2min),暂停所有任务的执行,进行mark&sweep操作,操作完成后启动所有任务的执行。在内存使用较多的场景下,go程序在进行垃圾回收时会发生非常明显的卡顿现象(Stop The World)。在对响应速度要求较高的后台服务进程中,这种延迟简直是不能忍受的!这个时期国内外很多在生产环境实践go语言的团队都或多或少踩过gc的坑。当时解决这个问题比较常用的方法是尽快控制自动分配内存的内存数量以减少gc负荷,同时采用手动管理内存的方法处理需要大量及高频分配内存的场景。

v1.3 Mark STW, Sweep 并行
1.3版本中,go runtime分离了mark和sweep操作,和以前一样,也是先暂停所有任务执行并启动mark,mark完成后马上就重新启动被暂停的任务了,而是让sweep任务和普通协程任务一样并行的和其他任务一起执行。如果运行在多核处理器上,go会试图将gc任务放到单独的核心上运行而尽量不影响业务代码的执行。go team自己的说法是减少了50%-70%的暂停时间。

v1.5 三色标记法
go 1.5正在实现的垃圾回收器是“非分代的、非移动的、并发的、三色的标记清除垃圾收集器”。引入了上文介绍的三色标记法,这种方法的mark操作是可以渐进执行的而不需每次都扫描整个内存空间,可以减少stop the world的时间。 由此可以看到,一路走来直到1.5版本,go的垃圾回收性能也是一直在提升,但是相对成熟的垃圾回收系统(如java jvm和javascript v8),go需要优化的路径还很长(但是相信未来一定是美好的~)。

v1.8 混合写屏障(hybrid write barrier)
这个版本的 GC 代码相比之前改动还是挺大的,采用一种混合的 write barrier 方式 (Yuasa-style deletion write barrier [Yuasa ‘90] 和 Dijkstra-style insertion write barrier [Dijkstra ‘78])来避免 堆栈重新扫描。

混合屏障的优势在于它允许堆栈扫描永久地使堆栈变黑(没有STW并且没有写入堆栈的障碍),这完全消除了堆栈重新扫描的需要,从而消除了对堆栈屏障的需求。重新扫描列表。特别是堆栈障碍在整个运行时引入了显着的复杂性,并且干扰了来自外部工具(如GDB和基于内核的分析器)的堆栈遍历。

此外,与Dijkstra风格的写屏障一样,混合屏障不需要读屏障,因此指针读取是常规的内存读取; 它确保了进步,因为物体单调地从白色到灰色再到黑色。

混合屏障的缺点很小。它可能会导致更多的浮动垃圾,因为它会在标记阶段的任何时刻保留从根(堆栈除外)可到达的所有内容。然而,在实践中,当前的Dijkstra障碍可能几乎保留不变。混合屏障还禁止某些优化:特别是,如果Go编译器可以静态地显示指针是nil,则Go编译器当前省略写屏障,但是在这种情况下混合屏障需要写屏障。这可能会略微增加二进制大小。

小结:

通过go team多年对gc的不断改进和忧化,GC的卡顿问题在1.8 版本基本上可以做到 1 毫秒以下的 GC 级别。 实际上,gc低延迟是有代价的,其中最大的是吞吐量的下降。由于需要实现并行处理,线程间同步和多余的数据生成复制都会占用实际逻辑业务代码运行的时间。GHC的全局停止GC对于实现高吞吐量来说是十分合适的,而Go则更擅长与低延迟。
并行GC的第二个代价是不可预测的堆空间扩大。程序在GC的运行期间仍能不断分配任意大小的堆空间,因此我们需要在到达最大的堆空间之前实行一次GC,但是过早实行GC会造成不必要的GC扫描,这也是需要衡量利弊的。因此在使用Go时,需要自行保证程序有足够的内存空间。

垃圾收集是一个难题,没有所谓十全十美的方案,通常是为了适应应用场景做出的一种取舍。

相信GO未来会更好。

参考:

https://github.com/golang/pro…

http://legendtkl.com/2017/04/…

https://blog.twitch.tv/gos-ma…

https://blog.plan99.net/moder…

links
目录

Go语言的垃圾回收机制,图文并茂 一篇搞懂! 根据Go语言垃圾回收机制的演进过程,详细分析了每一种方法(标记清除法、三色标记法、插入写屏障、删除写屏障、混合写屏障)的优缺点 阅读详情

相关推荐

Golang GC/垃圾回收机制

1、简介 Golang GC 算法使用的是无无分代(对象没有代际之分)、不整理(回收过程中不对对象进行移动与整理)、并发(与用户代码并发执行)的三色标记清扫算法。原因在于: 对象整理的优势是解决内存碎片问题以及“允许”使用顺序内存分配器。但 Go 运行时的分配算法基于tcmalloc,基本上没有碎片问题。 并且顺序内存分配器在多线程的场景下并不适用。Go 使用的是基于tcmalloc的现代内存分配算法,对对象进行整理不会带来实质性的性能提升。 分代 GC 依赖分代假设,即 GC 将主要的回收目标...

qq_35945759的博客 683

go GC(垃圾回收)

目录什么是GCgo语言中的GC标记清除法三色标记法两种不变式go对上述规则的两种实现机制:插入写屏障删除写屏障混合写屏障法总结 什么是GC GC 堆内存上分配的数据对象,不会再使用时,不会自动释放内存,就变成垃圾,在程序的运行过程中,如果不能及时清理,会导致越来越多的内存空间被浪费,导致系统性能下降。 因此需要内存回收,内存回收分为两种方式 1.手动释放占用的内存空间 可能会出现的问题: 悬挂指针: 释放的早了,后续对数据的访问就会出错,因为对应的内存空间可能已经清空,重新分配,甚至是归还给操作系统了。 内

weixin_45919793的博客 5874

【Golang】Golang的GC垃圾回收机制

在现代编程语言中,垃圾回收(Garbage Collection, GC)机制是一个至关重要的特性。它帮助开发者自动管理内存,避免内存泄漏和悬挂指针等问题。Go 语言(Golang)作为一门现代编程语言,内置了高效的垃圾回收机制。本文将深入探讨 Go 语言的 GC 机制,通过代码示例解释其工作原理,并展示如何优化代码以减少 GC 压力。o 语言的垃圾回收器主要基于标记-清除(Mark-and-Sweep)和三色标记(Tri-color Marking)算法。标记-清除(Mark-and-Sweep)

tr6666的博客 1419

Go的垃圾回收(GC),详细总结

详细的Go语言垃圾GC分析,包括GC的简介、根节点、GC的三色标记法、GC的屏障、GC的触发时机、GC的调优,以及GC的分析工具等

Dong_chongwu的博客 6611

EPS+ArcGIS+CASS三剑客:等高线裁剪的完整工作流与避坑指南

本文详细介绍了EPS、ArcGIS和CASS三款软件在等高线裁剪中的协同工作流程与避坑指南。通过发挥各软件优势,解决数据完整性、拓扑准确性和流程可靠性等核心挑战,提升40%以上的工作效率。特别适合大型测绘项目中复杂地形的处理,涵盖数据准备、核心处理到后期优化的全流程。

weixin_30352645的博客 617

基于FPGA的ov5640摄像头简易图像采集装置详解

本文介绍一种基于FPGA的,通过流模式DDR实现OV5640摄像头数据采集并显示的方法。

qq_42230252的博客 1万+

深入理解GO语言:GC原理及源码分析

Go 中的runtime 类似 Java的虚拟机,它负责管理包括内存分配、垃圾回收、栈处理、goroutine、channel、切片(slice)、map 和反射(reflection)等。Go 的可执行文件都比相对应的源代码文件要大很多,这是因为 Go 的 runtime 嵌入到了每一个可执行文件当中。 常见的几种gc算法: 引用计数:对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0是回收该对象。 优点:对象可以很快的被回收,不会出现内存耗尽或达到某个阀值时才回

cyq6239075的博客 5219

软件工程:数据字典

数据字典

永远怀着至诚之心拥抱世界 4273

go java gc_Golang GC(垃圾回收机制)

Golang GC1.常见的垃圾回收机制1.1 引用计数对每个对象维护一个引用计数,当引用对象的对象被销毁时,饮用计数-1,如果引用计数为0,则进行垃圾回收优点:对象可以很快的被回收,不会出现内存耗尽或达到某个阀值时才回收。缺点:不能很好的处理循环引用,而且实时维护引用计数,有也一定的代价。代表语言:Python、PHP、Swift1.2 标记-清除从根变量开始遍历所有引用的对象,引用的对象标记为...

weixin_31855625的博客 284

Mamba-ST实战:用状态空间模型实现艺术风格迁移的5个关键步骤

本文详细介绍了如何使用Mamba-ST状态空间模型实现高效的艺术风格迁移,涵盖环境配置、数据预处理、模型架构、训练策略和推理优化等5个关键步骤。Mamba-ST基于SSM(状态空间模型)构建,在保持生成质量的同时显著降低计算复杂度,为风格迁移领域提供了新的解决方案。

weixin_29163581的博客 354

手把手教你用UNI-MOL进行分子性质预测:从3D构象到实战结果

本文提供了使用UNI-MOL进行分子性质预测的完整实战指南。通过详细的环境搭建、3D构象生成、模型加载与微调步骤,手把手教你构建端到端的预测流水线。文章重点解析了如何利用UNI-MOL的3D分子表示学习能力,超越传统2D方法,实现对溶解度、活性等性质的更精准预测,并探讨了结果解读与模型分析方法。

weixin_29164091的博客 116

golang 的 gc垃圾回收机制

本文章主要介绍了golang中gc垃圾回收机制的运行原理,三色标记法,以及混合写屏障的机制。

感谢您的访问,期待和大家一起在Go语言的世界中共同进步 1711

亿佰特E77模块(STM32WLE5CCU6)LoRa通信实战指南:从配置到应用开发

本文详细介绍了亿佰特E77模块(STM32WLE5CCU6)的LoRa通信实战指南,从硬件配置到应用开发。基于ARM Cortex-M4内核的E77模块集成了LoRa射频前端,具备超低功耗和硬件级抗干扰特性,适用于智能农业、工业现场等场景。文章提供了开发环境搭建、LoRa参数配置、实战通信及性能优化等实用技巧,帮助开发者快速掌握LoRa通信技术。

weixin_29164185的博客 760

golang GC垃圾回收机制

** golang GC垃圾回收 ** 垃圾回收(Garbage Collection,简称GC)是编程语言中提供的自动的内存管理机制,自动释放不需要的对象,让出存储器资源,无需程序员手动执行。 Golang中的垃圾回收主要应用三色标记法,GC过程和其他用户goroutine可并发运行,但需要一定时间的STW(stop the world),STW的过程中,CPU不执行用户代码,全部用于垃圾回收,这个过程的影响很大,Golang进行了多次的迭代优化来解决这个问题。 一、Go 历史各个版本在 GC 方面的改进

qq_35679620的博客 1020

学Simulink--基础微电网场景实例:基于Simulink的微电网并网/孤岛无缝切换控制仿真

本文完成了基于 Simulink 的微电网并网/孤岛无缝切换控制仿真,实现了:✅ 构建含双模式逆变器的微电网模型✅ 实现预同步 + Stateflow 逻辑的智能切换✅ 验证计划与非计划切换的性能边界✅ 证明“无缝”在工程上是可实现的。

amy_mhd的博客 101

华为OD机试 - 城市聚集度(Python/JS/C/C++ 2025 A卷 200分)

华为OD机试 2025A卷题库疯狂收录中,刷题。

学Java,找哪吒 1129

Go中的GC垃圾回收机制详解

本文详细描述Golang语言中的GC垃圾回收机制的实现原理,帮助大家更好的理解Go中的GC

bojinyuan00的博客 1148

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

java golang gc_Golang GC 垃圾回收机制详解

摘要在实际使用 go 语言的过程中,碰到了一些看似奇怪的内存占用现象,于是决定对go语言的垃圾回收模型进行一些研究。本文对研究的结果进行一下总结。什么是垃圾回收?曾几何时,内存管理是程序员开发应用的一大难题。传统的系统级编程语言(主要指C/C++)中,程序员必须对内存小心的进行管理操作,控制内存的申请及释放。稍有不慎,就可能产生内存泄露问题,这种问题不易发现并且难以定位,一直成为困扰开发者的噩梦。...

weixin_33260484的博客 284

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Golang GC 垃圾回收机制详解

摘要 在实际使用 go 语言的过程中,碰到了一些看似奇怪的内存占用现象,于是决定对go语言的垃圾回收模型进行一些研究。本文对研究的结果进行一下总结。 什么是垃圾回收? 曾几何时,内存管理是程序员开发应用的一大难题。传统的系统级编程语言(主要指C/C++)中,程序员必须对内存小心的进行管理操作,控制内存的申请及释放。稍有不慎,就可能产生内存泄露问题,这种问题不易发现并且难以定位,一直成为困扰开...

早先生 1289

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Go GC垃圾回收机制

1、垃圾回收 曾几何时,内存管理是程序员开发应用的一大难题。传统的系统级编程语言(主要指C/C++)中,程序员必须对内存小心的进行管理操作,控制内存的申请及释放。稍有不慎,就可能产生内存泄露问题,这种问题不易发现并且难以定位,一直成为困扰开发者的噩梦。如何解决这个头疼的问题呢?过去一般采用两种办法: (1)内存泄露检测工具。这种工具的原理一般是静态代码扫描,通过扫描程序检测可能出现内存泄露的代码段。然而检测工具难免有疏漏和不足,只能起到辅助作用。 (2)智能指针。这是 c++ 中引入的自动内存管理方法,通过

weixin_42282999的博客 925

Golang怎么理解GC垃圾回收机制_Golang如何分析和优化Go的内存回收性能【详解】

GC 什么时候真正回收内存给操作系统?用 go tool trace 查看 Scavenger goroutine 活动,确认是否真在清扫,而不是卡在“等超时”生产环境别依赖 GOGC=10 这类低阈值调优来“加速释放”,它只影响 GC 触发频率,不影响归还 OS 的时机若服务 RSS 持续偏高但 HeapInuse 很低,大概率是大量 span 空闲未 scavenged,可临时设 GOMEMLIMIT=80% of RSS 压一压为什么 pprof 看不到“内存泄漏”,但 RSS 还是一路涨?

tjc19901005的博客 241

Golang GC(垃圾回收机制)及内存逃逸

GO :垃圾回收机制(GC: Garbage Collection) 阻塞状态是go调度的一个待唤醒的状态,是不能被gc的。 go V1.3之前 采用的gc是标记回收法(mark&sweep): 从根变量来时遍历所有被引用对象,标记之后进行清除操作,对未标记对象进行回收 标记回收法的缺点是: 1、STW:stop the world; 让程序暂停,程序出现卡顿、 2、标记需要扫描整个堆heap 3、标记会产生he...

qq_33690342的博客 3163

Go的垃圾回收机制(GC)你真的理解了吗?

而传统的垃圾回收(如 Java 的 Stop-The-World GC)虽然解决了内存安全问题,但往往带来显著的延迟峰值。:Go 的垃圾回收机制是一个精心设计的系统,它在保证内存安全的同时,最大限度地减少了对程序性能的影响。理解 GC 的工作原理不仅能帮助我们写出更高效的代码,更能让我们在面对性能问题时有的放矢。希望通过本文的深入分析,你能够真正理解 Go GC 的精髓,并在实际项目中应用这些知识。基于"大部分对象都是短生命周期"的观察,将对象分为不同代,对不同代采用不同的回收策略。请给出具体的实现思路。

qq_36047859的博客 533
上一篇: MySQL之MVVC简介
下一篇: 2018年经历过的一些事情
牧竹子
博客等级 码龄17年 572粉丝 233原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值