Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

这篇文章基于 Go 1.13 版本。有关内存管理的讨论在我的文章 ”Go:内存管理与分配 ” 中有解释。

清理内存是一个过程,它能够让 Go 知道哪些内存段最近可用于分配。但是,它并不会使用将位置 0 的方式来清理内存。

将内存置 0

将内存置 0 的过程 —— 就是把内存段中的所有位赋值为 0 —— 是在分配过程中即时执行的。

Zeroing the memory

但是,我们可能想知道 Go 采用什么样的策略去知道哪些对象能够用于分配。由于在每个范围内有一个内部位图 allocBits ,Go 实际上会追踪那些空闲的对象。让我们从初始态开始来回顾一下它的工作流程,

Free objects tracking with allocBits

就性能角度来看,allocBits 代表了一个初始态并且会保持不变,但是它会由 freeIndex(一个指向第一个空闲位置的增量计数器)所协助。

然后,第一个分配就开始了:

Free objects tracking with allocBits

freeIndex 现在增加了,并且基于 allocBits 知道了下一段空闲位置。

分配过程将会再一次出现,之后, GC 将会启动去释放不再被使用的内存。在标记期间,GC 会用一个位图 gcmarkBits 来跟踪在使用中的内存。让我们通过我们运行的程序以相同的示例为例,在第一个块不再被使用的地方。

Memory tracking during the garbage collector

正在被使用的内存被标记为黑色,然而当前执行并不能够到达的那些内存会保持为白色。

有关更多关于标记和着色阶段的信息,我建议你阅读我的这篇文章 Go:GC 是如何标记内存的? 现在,我们可以使用 gomarkBits 精确查看可用于分配的内存。Go 现在也使用 gomarkBits 代替了 allocBits ,这个操作就是内存清理:

Sweeping a span

但是,这必须在每一个范围内执行完毕并且会花费许多时间。Go 的目标是在清理内存时不阻碍执行,并为此提供了两种策略。

清理阶段

Go 提供了两种方式来清理内存:

  • 使用一个工作程序在后台等待,一个一个的清理这些范围。
  • 当分配需要一个范围的时候即时执行。

关于后台工作程序,当开始运行程序时,Go 将设置一个后台运行的 Worker(唯一的任务就是去清理内存),它将进入睡眠状态并等待内存段扫描:

Background sweeper

通过追踪过程的周期,我们也能看到这个后台工作程序总是出现去清理内存:

Background sweeper

清理内存段的第二种方式是即时执行。但是,由于这些内存段已经被分发到每一个处理器的本地缓存 mcache 中,因此很难追踪首先清理哪些内存。这就是为什么 Go 首先将所有内存段移动到 mcentral 的原因。

Spans are released to the central list

然后,它将会让本地缓存 mcache 再次请求它们,去即时清理:

Sweep span on the fly during allocation

即时扫描确保所有内存段在保存资源的过程中都会得到清理,同时会保存资源以及不会阻塞程序执行。

与 GC 周期的冲突

正如之前看到的,由于后台只有一个 worker 在清理内存块,清理过程可能会花费一些时间。但是,我们可能想知道如果另一个 GC 周期在一次清理过程中启动会发生什么。在这种情况下,这个运行 GC 的 Goroutine 就会在开始标记阶段前去协助完成剩余的清理工作。让我们举个例子看一下连续调用两次 GC,包含数千个对象的内存分配的过程。

Sweeping must be finished before a new cycle

但是,如果开发者没有强制调用 GC,这个情况并不会发生。在后台运行的清理工作以及在执行过程中的清理工作应该足够多,因为清理内存块的数量和去触发一个新的周期(译者注:GC 周期)的所需的分配的数量成正比。


作者:Vincent Blanchon 译者:sh1luo 校对:polaris1119

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

Go:内存管理与内存清理的更多相关文章

  1. 【R笔记】R的内存管理和垃圾清理

    笔记: 1.R输入命令时速度不要太快,终究是个统计软件,不是编程! 2.memory.limit()查看当前操作系统分配内存给R的最大限度(单位是M?) 3.要经常 rm(object) 或者 rm( ...

  2. SAP专家培训之Netweaver ABAP内存管理和内存调优最佳实践

    培训者:SAP成都研究院开发人员Jerry Wang 1. Understanding Memory Objects in ABAP Note1: DATA itab WITH HEADER LINE ...

  3. R内存管理与垃圾清理

    1.内存查看 memory.limit():查看内存大小 memory.limit(n):申请内存大小 memory.size(NA):查看内存大小 memory.size(T):查看已分配的内存 m ...

  4. Java的内存管理与内存泄露

    作为Internet最流行的编程语言之一,Java现正非常流行.我们的网络应用程序就主要采用Java语言开发,大体上分为客户端.服务器和数据库三个层次.在进入测试过程中,我们发现有一个程序模块系统内存 ...

  5. davlik虚拟机内存管理之一——内存分配

    转载自http://www.miui.com/thread-74715-1-1.html dalvik虚拟机是Google在Android平台上的Java虚拟机的实现,内存管理是dalvik虚拟机中的 ...

  6. Delphi的内存管理及内存泄露问题 FastMM4

    这几天因为一个程序长时间运行出现比较严重的内存泄露问题,开始关注了一下内存管理方面的东西,以前也注意内存管理,创建了对象及时释放,但总有忘了处理的情况. 在Delphi中没有自动回收机制,所以一定要及 ...

  7. window内存管理与内存原理

    转自: http://blog.csdn.net/iamfranter/article/details/6826270 WIndows为每个进程分配了4GB的虚拟地址空间,让每个进程都认为自己拥有4G ...

  8. Objective-C 【内存管理&手动内存管理 综述】

    ------------------------------------------- 内存管理 (1)Objective-C的内存管理 栈区    存放局部变量(由于基本数据类型占用的存储空间是固定 ...

  9. Android 之 内存管理-查看内存泄露(三)

    概述 在android的开发中,要时刻主要内存的分配和垃圾回收,因为系统为每一个dalvik虚拟机分配的内存是有限的,在google的G1中,分配的最大堆大小只有16M,后来的机器一般都为24M,实在 ...

随机推荐

  1. matlab 打包exe

    mcc -m gui_abc.m https://blog.csdn.net/hujiameihuxu/article/details/53525373 deploytool app compiler

  2. C# - 设计- Struct与Class的选择

    选择Struct的原则 该类型的实例较小且通常为短生存期,或者通常嵌入到其他对象中. 它以逻辑方式表示单个值,类似于基元类型( int .等 double ). 它的实例大小为16字节. 它是不可变的 ...

  3. c++运行程序 改变字和背景的颜色与窗口大小和位置 (c++)(windows)

    关于改变字体的颜色和背景颜色: 在#include <windows.h> 库里 0=黑色 1=蓝色 2=绿色 3=湖蓝色 4=红色 5=紫色 6=黄色 7=白色 8=灰色 9=淡蓝色 A ...

  4. bzoj2295【POJ Challenge】我爱你啊*

    bzoj2295[POJ Challenge]我爱你啊 题意: 求一个字符串中有多少个"luvletter"(不包括引号).字符串长度≤100000. 题解: 连kmp都不用…… ...

  5. 设计模式:abstract factory模式

    含义:抽象工厂将“抽象零件”组装成“抽象产品” 理解:相比于工厂方法模式,可以根据不同的接口创建不同的产品,说白了就是将一个接口变成两个接口,各自返回不同的抽象产品 例子: class Car //抽 ...

  6. [redis] -- 集群篇

    三种集群方式 主从同步:主从复制模式中包含一个主数据库实例(master)与一个或多个从数据库实例(slave) 优点: master能自动将数据同步到slave,可以进行读写分离,分担master的 ...

  7. 题解 洛谷 P4546 【[THUWC2017]在美妙的数学王国中畅游】

    首先发现有连边和删边的操作,所以我们肯定要用\(LCT\)来进行维护. 接下来考虑如何进行\(LCT\)上的信息合并. \(f=1\),则函数为\(f(x)=sin(ax+b)\) \(f=2\),则 ...

  8. CentOS7编译安装php7.1配置教程详解

    这篇文章主要介绍CentOS7编译安装php7.1的过程和配置详解,亲测 ,需要的朋友可以参考. 1.首先安装依赖包: yum install libxml2 libxml2-devel openss ...

  9. DJANGO-天天生鲜项目从0到1-002-用户模块-注册

    本项目基于B站UP主‘神奇的老黄’的教学视频‘天天生鲜Django项目’,视频讲的非常好,推荐新手观看学习 https://www.bilibili.com/video/BV1vt41147K8?p= ...

  10. BUUCTF-Web Comment

    dirsearch扫出/.git/目录 遂用航神写的Githacker脚本   https://github.com/wangyihang/githacker 出来的源码并不完整,使用git log ...