Golang内存管理——堆分配

news2024/9/20 17:26:37

go语言的内存自动分配和回收的,因此内存的使用流程大致为:获取内存——分配内存——回收内存——再分配内存。

其中分配内存分为两方面,堆内存分配和栈内存分配,堆内存和栈内存是两种不同的分配方式,本篇文章主要是堆内存的分配方式。

1. 自主内存管理

Go语言为了方便内存的自主管理,一开始启动的时候会向操作系统申请一大块连续的内存,后续的内存分配都是基于这一大块内存的。如果程序运行过程中,内存不足了,Go语言会再向操作系统进行内存的申请。

为了高效的进行内存管理,Go语言将申请到的内存划分为三个区域,分别为spans、bitmap、arena。其中arena是堆区,GO语言将其划分为一个个8KB的page页,程序运行过程中的内存都是从arena堆区进行分配的。spans和bitmap是为了对arena堆区的高效管理而设置的。

Go语言的三个内存区域

2. mspan 和 ClassID表

我们程序的运行,从使用的角度看,以对象为基本单位的。比如:函数是一个对象、goroutine是一个对象、slice是一个对象。因此,为了实现从对象到内存页之间的映射,Go语言引入了一个mspan结构体。mspan是内存管理的基本单位,每一个span包含一个或多个连续的页。为了满足小对象的分配,会将span中的一页划分为更小的粒度,而对于大对象比如超过页的大小,则会通过多页实现。每个span用于管理特定的class对象,根据对象的大小,span将一个或多个页拆分成多个块进行管理。

mspan的结构体定义如下:位置 runtime:mheap.go 一些字段已经省略了

type mspan struct {
	next *mspan     // 链表后向指针,用于将span链接起来
	prev *mspan     // 链表前向指针,用于将span链接起来
	startAddr uintptr // 起始地址,即所管理页的地址
	npages    uintptr // 该span中占用的page页数

    //作用于GC,垃圾会有的时候会使用这三个字段
	allocBits  *gcBits //分配位图,每一位代表一个块是否已分配
	gcmarkBits *gcBits
	pinnerBits *gcBits 

	allocCount  uint16        // 该Span中已经分配的对象数量
	spanclass   spanClass     // 该Span的等级,一个特定的span中存储特定的ClassID大小的对象
	elemsize    uintptr       // 块大小,该span中存储特定ClassID的大小
}

 Class等级列表如下:
源码位置:runtime:sizeclasses.go

划分如此多的Class等级的目的:

  1. 尽可能地减少内存浪费
  2. 降低从全局缓存中获取特定SpanClass锁的粒度
// class  bytes/obj  bytes/span  objects  tail waste  max waste  min align
//     1          8        8192     1024           0     87.50%          8
//     2         16        8192      512           0     43.75%         16
//     3         24        8192      341           8     29.24%          8
//     4         32        8192      256           0     21.88%         32
//     5         48        8192      170          32     31.52%         16
//     6         64        8192      128           0     23.44%         64
//     7         80        8192      102          32     19.07%         16
//     8         96        8192       85          32     15.95%         32
//     9        112        8192       73          16     13.56%         16
//    10        128        8192       64           0     11.72%        128
//    11        144        8192       56         128     11.82%         16
//    12        160        8192       51          32      9.73%         32
//    13        176        8192       46          96      9.59%         16
//    14        192        8192       42         128      9.25%         64
//    15        208        8192       39          80      8.12%         16
//    16        224        8192       36         128      8.15%         32
//    17        240        8192       34          32      6.62%         16
//    18        256        8192       32           0      5.86%        256
//    19        288        8192       28         128     12.16%         32
//    20        320        8192       25         192     11.80%         64
//    21        352        8192       23          96      9.88%         32
//    22        384        8192       21         128      9.51%        128
//    23        416        8192       19         288     10.71%         32
//    24        448        8192       18         128      8.37%         64
//    25        480        8192       17          32      6.82%         32
//    26        512        8192       16           0      6.05%        512
//    27        576        8192       14         128     12.33%         64
//    28        640        8192       12         512     15.48%        128
//    29        704        8192       11         448     13.93%         64
//    30        768        8192       10         512     13.94%        256
//    31        896        8192        9         128     15.52%        128
//    32       1024        8192        8           0     12.40%       1024
//    33       1152        8192        7         128     12.41%        128
//    34       1280        8192        6         512     15.55%        256
//    35       1408       16384       11         896     14.00%        128
//    36       1536        8192        5         512     14.00%        512
//    37       1792       16384        9         256     15.57%        256
//    38       2048        8192        4           0     12.45%       2048
//    39       2304       16384        7         256     12.46%        256
//    40       2688        8192        3         128     15.59%        128
//    41       3072       24576        8           0     12.47%       1024
//    42       3200       16384        5         384      6.22%        128
//    43       3456       24576        7         384      8.83%        128
//    44       4096        8192        2           0     15.60%       4096
//    45       4864       24576        5         256     16.65%        256
//    46       5376       16384        3         256     10.92%        256
//    47       6144       24576        4           0     12.48%       2048
//    48       6528       32768        5         128      6.23%        128
//    49       6784       40960        6         256      4.36%        128
//    50       6912       49152        7         768      3.37%        256
//    51       8192        8192        1           0     15.61%       8192
//    52       9472       57344        6         512     14.28%        256
//    53       9728       49152        5         512      3.64%        512
//    54      10240       40960        4           0      4.99%       2048
//    55      10880       32768        3         128      6.24%        128
//    56      12288       24576        2           0     11.45%       4096
//    57      13568       40960        3         256      9.99%        256
//    58      14336       57344        4           0      5.35%       2048
//    59      16384       16384        1           0     12.49%       8192
//    60      18432       73728        4           0     11.11%       2048
//    61      19072       57344        3         128      3.57%        128
//    62      20480       40960        2           0      6.87%       4096
//    63      21760       65536        3         256      6.25%        256
//    64      24576       24576        1           0     11.45%       8192
//    65      27264       81920        3         128     10.00%        128
//    66      28672       57344        2           0      4.91%       4096
//    67      32768       32768        1           0     12.50%       8192

3. mcentral 和 mcache

首先,我们申请内存是以goroutine为单位的(也可以说是线程),以线程为单位去获取对应的span。其次为了方便对span的管理,我们需要引入结构体来管理span。结构体就是mcentral。mcentral是一个全局的缓存,各线程需要内存的时候,从central中获取对应的span。为了避免多线程申请内存的时候,不断进行加锁。Go为每一个线程设置了一个本地缓存,也就是mcache。每一个线程需要内存的时候,优先从本地缓存mcache中获取对应的span,如果本地缓存中不存在对应的span,则会从全局队列mcentral中获取。

mcache和mcentral的结构体定义如下:runtime:mcentral.go 和 runtime:mcache.go

// 给定大小的空闲对象全局缓存,一个全局缓存存储特定ClassID的span
type mcentral struct {
	_         sys.NotInHeap
	spanclass spanClass //存储的特定的classID的span

	partial [2]spanSet // 还有空闲块的span列表
	full    [2]spanSet // 无空闲块的span列表
}



// 每一个线程(在Go中,指的是每一个P)都有一个mcache小对象
// 进行操作的时候,不需要锁,因为它是属于每个线程的
type mcache struct {

	alloc [2*68]*mspan // 本cache中被分配的跨度,索引是span对应的classID

	stackcache [_NumStackOrders]stackfreelist //线程中执行栈的空闲span链表
}

以上源码的部分都经过了省略,字段展示的不全,想要深入了解的朋友,自行浏览。

从以上结构体的定义中,我们可以发现,mcache中有所有ClassID的span链表,而mcentral只管理特定ClassID的span。所以,在mcentral上层,应该还有一个结构体,去管理所有ClassID的mcentral,这个结构体就是mheap。

4. mheap

// 分配堆
type mheap struct {
	lock mutex

	/*allspans存储所有已创建的mspan的切片。每个mspan只出现一次
	通常,allspans被mheap的锁保护,防止并发访问,并释放后台存储。*/
	allspans []*mspan // all spans out there

	// 所有的central列表
	central [2*68]struct {
		mcentral mcentral
		pad      [(cpu.CacheLinePadSize - unsafe.Sizeof(mcentral{})%cpu.CacheLinePadSize) % cpu.CacheLinePadSize]byte
	}
}

从上面的mheap结构体的定义,可以发现,mheap是顶级内存分配,通过管理各种类型的mcentral。实际上,Go语言就是通过mheap来管理arean堆区的所有内存的。

5. 申请size为n的内存,分配步骤如下:

为了提升内存分配的效率,当程序执行时可以从优先mcache,mcentral、mheap这三个地方获取内存。

1、对于小于小于等于32kb的内存,优先在mcache (无锁,效率最高) 获取,如果mcache 中没有空闲则从mcentral中获取(有锁,效率次之),mcentral中没有空闲的span,这时候从mheap 中获取(全局锁,效率最低),如果mheap 中也没有可用的span则向操作系统申请(发生系统调用,效率最差)。

2、对于大于32kb 则去mheap 获取,如果没有空闲span 则从系统申请。

6. 总结

内存分配是Go语言的基础,涉及的内容比较多,关联操作系统、用户程序、GC垃圾回收等部分,是一个大难点。目前这篇文章可能存在一些问题,如果可以发现,请指正交流

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

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

相关文章

Leetcode刷题——9 基本数据结构(哈希表,并查集)

注&#xff1a;以下代码均为c 1. 哈希表 1.1 重复的DNA序列 什么数据结构既可以保存数据又可以计数&#xff1a;哈希表 vector<string> findRepeatedDnaSequences(string s) {unordered_map<string, int> hash;vector<string> ans;for(int i 0; i 10 &l…

Docker部署RabbitMQ指南

1. Rabbit概述 RabbitMQ是基于Erlang语言开发的开源消息通信中间件&#xff0c;官方地址&#xff1a;https://www.rabbitmq.com/。 2. 单机部署 我们在CentOS7虚拟机中使用Docker来安装。 2.1 下载镜像 方式一&#xff1a;在线拉取 docker pull rabbitmq:3-management 方…

Linux 内核源码分析---文件系统关联与字符设备操作

文件系统关联 设备文件都是由标准函数处理&#xff0c;类似于普通文件。设备文件也是通过虚拟文件系统来管理的&#xff0c;和普通文件都是通过完全相同的接口访问。 inode 中设备文件的成员数据 虚拟文件系统每个文件都关联到一个 inode&#xff0c;用于管理文件的属性。 …

RIP、OSPF 协议详解 / Stub/Totally Stub/NSSA/Totally NSSA 区域测试

注&#xff1a;原出处 https://javaforall.cn/204275.html 图片已挂。下文来自 腾讯云 全栈君 RIP、OSPF 协议详解 1、路由协议简介 在互联网中&#xff0c;一个自治系统 (AS) 是一个有权自主地决定在本系统中应采用何种路由协议的小型单位。这个网络单位可以是一个简单的网络…

我们如何提高 Baklib 的 SEO 性能

搜索引擎已经成为我们日常生活中不可或缺的一部分&#xff1b;谷歌甚至成为英语中的动词。因此&#xff0c;每个企业都需要关注其搜索引擎排名。在 Baklib&#xff0c;我们最近遇到了 SEO 排名的挑战。因此&#xff0c;在我们讨论这个问题之前&#xff0c;让我们先了解一下爬行…

宠物空气净化器可以除毛吗?室内浮毛空气净化器推荐

家里养了5只猫&#xff0c;满天飞的猫毛发&#xff0c;随风飘到各个角落&#xff0c;可以说苦不堪言。真的不建议养猫&#xff0c;除非你能接受空气中飞舞着浮毛&#xff0c;衣服、床、筷子、鼻子里全都是猫毛&#xff0c;拉臭臭有异味等等。感觉到处都被猫毛覆盖了&#xff0c…

【多线程】线程状态与并发三大特性的细节剖析

这篇文章主要用于对于多线程的一些查缺补漏。 一、 线程的状态 1&#xff0c;操作系统层面&#xff0c;线程的5种状态 关于线程有几种状态&#xff0c;有多种说法&#xff0c;5、6、7都有。 首先对于操作系统来说&#xff0c;只有5种状态&#xff0c;状态如下新建&#xff…

mac|安装hashcat(压缩包密码p解)

一、安装Macports&#xff08;如果有brew就不用这一步&#xff09; 根据官网文档&#xff1a;The MacPorts Project -- Download & Installation&#xff0c;安装步骤如下 1、下载MacPorts&#xff0c;这里我用的是tar.gz &#xff0c;可以通过keka&#xff08;keka安装在…

《pygame游戏开发实战指南》第三节 理解pygame中的坐标体系

pygame中的坐标体系非常的简单&#xff0c;其实就是一句话&#xff1a;任何对象的左上角都为坐标原点(0, 0)&#xff0c;向右为X轴正方向&#xff0c;向下为Y轴正方向。如下图所示。本节主要通过一些示例来带大家理解这一句话。如果读者已经理解的话&#xff0c;可以直接跳过这…

iPhone不下载APP直接投屏到电脑,这些投影设置你会用吗【电脑投影设置需添加】

最近小编一直在追唐朝诡事录之西行&#xff0c;太好看了&#xff0c;就是手机屏幕有点小&#xff0c;虽然也可以在电脑上看&#xff0c;但是小编心血来潮想投屏到此电脑看看&#xff0c;因此就写了这篇文章。 ①首先打开电脑的设置&#xff0c;打开系统 ②左侧栏中找到投影到此…

学习Java的日子 Day63 文件上传,文件下载,上传头像案例

文件上传下载 1.文件上传 文件上传的应用 比如个人信息的管理&#xff0c;上传头像 比如商品信息的管理&#xff0c;上传商品的图片 这些都需要通过浏览器客户端将图片上传到服务器的磁盘上 2.文件上传原理 所谓的文件上传就是服务器端通过request对象获取输入流&#xff0c;将…

VMware安装Centos虚拟机使用NAT模式无法上网问题处理

NAT模式无法上网问题处理 Centos7与Ubuntu使用同一个NAT网络&#xff0c;Ubuntu正常访问互联网&#xff0c;Centos无法正常访问。 处理方案&#xff1a; cd /etc/sysconfig/network-scripts vi ifcfg-ens33 修改配置项&#xff1a; 重启网络&#xff1a; service network resta…

vue的nextTick是下一次事件循环吗

如题&#xff0c;nextTick的回调是在下一次事件循环被执行的吗&#xff1f; 是不是下一次事件循环取决于nextTick的实现&#xff0c;如果是用的微任务&#xff0c;那么就是本次事件循环&#xff1b;否则如果用的是宏任务&#xff0c;那么就是下一次事件循环。 我们看下Vue3中…

STM32L051K8U6-开发资料

STM32L051测试 &#xff08;四、Flash和EEPROM的读写&#xff09;-云社区-华为云 (huaweicloud.com) STM32L051测试 &#xff08;四、Flash和EEPROM的读写&#xff09; - 掘金 (juejin.cn) STM32L0 系列 EEPROM 读写&#xff0c;程序卡死&#xff1f;_stm32l0片内eeprom_stm3…

Android studio配置代码模版

一、背景&#xff1a; 在工作中&#xff0c;总是要写一些重复的代码&#xff0c;特别是项目有相关规范时&#xff0c;就会产生很多模版代码&#xff0c;每次要么复制一份&#xff0c;要么重新写一份新的&#xff0c;很麻烦&#xff0c;于是我就在想&#xff0c;能不能像创建一…

tomato靶场

扫描网址端口 访问一下8888 我们用kali扫描一下目录 访问这个目录 产看iofo.php源码&#xff0c;发现里面有文件包含漏洞 访问/etc/passwd/发现确实有文件包含漏洞 远程连接2211端口 利用报错&#xff0c;向日志文件注入木马&#xff0c;利用文件包含漏洞访问日志文件 http:/…

现代前端架构介绍(第二部分):如何将功能架构分为三层

远离JavaScript疲劳和框架大战&#xff0c;了解真正重要的东西 在这个系列的前一部分 《App是如何由不同的构建块构成的》中&#xff0c;我们揭示了现代Web应用是由不同的构建块组成的&#xff0c;每个构建块都承担着特定的角色&#xff0c;如核心、功能等。在这篇文章中&#…

手机市场回暖,为何OPPO却“遇冷”?

在智能手机这片红海中&#xff0c;OPPO曾以其独特的营销策略和创新的产品设计&#xff0c;一度占据国内市场的领先地位。然而&#xff0c;近期的数据却揭示了OPPO正面临前所未有的挑战&#xff0c;销量下滑、库存高企&#xff0c;昔日的辉煌似乎已成过眼云烟。 当整个手机市场逐…

单个或两个及以上java安装与环境变量配置

目录 java下载地址&#xff1a; 1.安装java 1.1 安装程序 1.2选择安装路径 1.3等待安装 2.首先&#xff0c;进入环境变量 2.1 找到设置&#xff08;第一个win11&#xff0c;第二个win10&#xff09; 2.2 进入到系统高级系统设置&#xff08;第一个win11&#xff0c;第二…

快捷生成vue模板插件

Vetur < 就可以选择快捷键