简单的说说: Golang 垃圾回收机制 ,可我说不出来 您所在的位置:网站首页 go语言模板垃圾 简单的说说: Golang 垃圾回收机制 ,可我说不出来

简单的说说: Golang 垃圾回收机制 ,可我说不出来

2023-03-30 20:44| 来源: 网络整理| 查看: 265

前言

Google 搜索 Golang GC 排名靠前的文章都讲的不错,从设计到实现,从演进到源码,一应俱全。但是庞杂的信息会给人一种恐惧感,让人望而却步。

本文尝试使用较为简单易懂的语言和图像,讲解 Golang 的垃圾回收机制。

垃圾回收算法

目前比较常见的垃圾回收算法有三种:

引用计数:为每个对象维护一个引用计数,当引用该对象的对象销毁时,引用计数 -1,当对象引用计数为 0 时回收该对象。

代表语言:Python、PHP、Swift优点:对象回收快,不会出现内存耗尽或达到某个阈值时才回收。缺点:不能很好的处理循环引用,而实时维护引用计数也是有损耗的。

标记-清除:从根变量开始遍历所有引用的对象,标记引用的对象,没有被标记的进行回收。

代表语言:Golang(三色标记法)优点:解决了引用计数的缺点。缺点:需要 STW,暂时停掉程序运行。

分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,短的放入新生代,不同代有不同的回收算法和回收频率。

代表语言:Java优点:回收性能好缺点:算法复杂

Golang 垃圾回收

跳过原理,我们先来介绍 Golang 的三色标记法。

三色标记法1 三色含义白色对象 — 潜在的垃圾,其内存可能会被垃圾收集器回收;黑色对象 — 活跃的对象,包括不存在任何引用外部指针的对象以及从根对象可达的对象;灰色对象 — 活跃的对象,因为存在指向白色对象的外部指针,垃圾收集器会扫描这些对象的子对象;2 根对象

垃圾回收中最先检测的对象,包括以下三种对象

全局变量:程序在编译期就能确定的那些存在于程序整个生命周期的变量。执行栈:每个 goroutine 都包含自己的执行栈,这些执行栈上包含栈上的变量及指向分配的堆内存区块的指针。寄存器:寄存器的值可能表示一个指针,参与计算的这些指针可能指向某些赋值器分配的堆内存区块。3 工作原理

在垃圾收集器开始工作时,程序中不存在任何的黑色对象,垃圾收集的根对象会被标记成灰色,垃圾收集器只会从灰色对象集合中取出对象开始扫描,当灰色集合中不存在任何对象时,标记阶段就会结束

具体流程如下图:

回收原理

通过上图,应该对三色标记法有了一个比较直观的了解,那么我们现在来讲讲原理。简单的讲,就是标记内存中那些还在使用中(即被引用了)的部分,而内存中不再使用(即未被引用)的部分,就是要回收的垃圾,需要将其回收,以供后续内存分配使用。

上图中的 A、B、D 就是被引用正在使用的内存,而 C、F、E 曾经被使用过,但现在没有任何对象引用,就需要被回收掉。

而 Root 区域主要是程序运行到当前时刻的栈和全局数据区域,是实时正在使用到的内存,当然应该优先标记。而考虑到内存块中存放的可能是指针,所以还需要递归的进行标记,待全部标记完后,就会对未被标记的内存进行回收。

内存标记

golang 中采用 span 数据结构管理内存,span 中维护了一个个内存块,并由一个位图 allocBits 表示内存块的分配情况,而上文中提到的 gcmarkBits 是记录每块内存块被引用情况的。

如上图,allocBits 记录了每块内存的分配情况,而 gcmarkBits 记录了每块内存的标记情况。

在标记阶段会对每块内存进行标记,有对象引用的内存标记为 1,没有对象引用的为 0。

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

三.详细介绍1 golang 三色标记法

golang 的垃圾回收采用的是 标记-清理(Mark-and-Sweep) 算法就是先标记出需要回收的内存对象快,然后清理,使用就是三色标记法。

2 gc 内存泄漏根本原因

预期的能很快被释放的内存由于附着在了长期存活的内存上,或生命期意外的被延长,导致预计能够立即回收的内存长时间得不到回收(由于 goroutine 还有多种形式)

预期能被快速释放的内存因被根对象引用而没有得到迅速释放

当有一个全局对象时,可能不经意间将某个变量附着在其上,且忽略的将其进行释放,则该内存永远不会得到释放

var cache = map[interface{}]interface{}{} func keepalloc() { for i := 0; i < 10000; i++ { m := make([]byte, 1


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有