Golang内存模型总结1(mspan、mcache、mcentral、mheap)
1.内存模型
1.1 操作系统存储模型
从上到下分别是寄存器、高速缓存、内存、磁盘,其中越往上速度越快,空间越小,价格越高。
关键词是多级模型和动态切换
1.2 虚拟内存与物理内存
虚拟内存是一种内存管理技术,允许计算机使用比物理内存更多的内存资源,通过将部分内存存储在硬盘上的方式,扩展了系统的可用内存。
1.3 分页管理
操作系统会把虚拟内存和物理内存切割成固定的尺寸,于虚拟内存而言叫做“页”,于物理内存而言叫“帧”,原因如下:
- 提高内存空间利用,减少外部碎片,内部碎片相对可控
- 提高内外存交换的效率,更细的粒度带来了更高的灵活度
- 与虚拟内存机制呼应,便于使用页表建立虚拟地址到物理地址之间的映射
- linux 页/帧的大小固定为4KB,实践得到的经验值,太大的话会增加碎片率,太小的话增加分配频率影响效率
1.4 Golang内存模型
几个核心的设计要点:
- 空间换时间,一次缓存,多次复用:因为每次向操作系统申请内存的操作很重,那么不妨一次多申请一些,以备后用。Golang的堆mheap正是基于该思想产生的数据结构,对于操作系统而言,这是用户进程中缓存的内存;对于Go进程内部,堆是所有对象的内存起源。
- 多级缓存,实现无/细锁化:堆是Go运行时最大的临界共享资源,这意味着每次存取都要加锁,很影响性能。为了解决这个问题,Golang依次细化粒度,建立了mcentral,mcache的模型:
- mheap:全局的内存起源,访问要加全局锁。数量只有1个
- mcentral:每种对象大小规格对应的缓存,锁的粒度仅仅局限于同一种规格里,全局划分为68份。(BigCache也用到了类似的思想)数量有68*2个(详细见2.3)
- mcache:每个P(即goroutine 内核线程)持有的一份内存缓存,访问时没有锁。数量等于P的数量
- 多级规格,提高利用率:
- page:最小的存储单元,借鉴操作系统分页管理的思想,每个最小的存储单元也称之为页,但是大小为8KB
- mspan:最小的管理单元,大小是page的整数倍,从8B到80KB被划分为67种不同的规格,分配对象时,会根据大小映射到不同规则的mspan,从中获取空间。产生的特点
- 根据规格大小,产生了等级的制度,才使得central支持细锁化
- 消除了外部碎片,但是不可避免地会有内部碎片
- 宏观上能提高整体空间利用率
2.核心概念
2.1 内存单元mspan
mspan是Golang内存管理地最小单元,大小是page地整数倍,而且内部的页是连续的。
每个mspan会根据空间大小以及面向分配对象的大小,被划分为不同的等级,同等级的mspan会从属一个mcentral,最终被组织成链表,带有前后指针(prev/next),而且因为同属一个mcentral,所以是基于同一把互斥锁管理。
基于bitMap辅助快速找到空闲内存块,块大小为对应等级下的object大小,这里用到了Ctz64算法
type mspan struct {// 标识前后节点的指针 next *mspan prev *mspan // ...// 起始地址startAddr uintptr // 包含几页,页是连续的npages uintptr // 标识此前的位置都已被占用 freeindex uintptr// 最多可以存放多少个 objectnelems uintptr // number of object in the span.// bitmap 每个 bit 对应一个 object 块,标识该块是否已被占用allocCache uint64// ...// 标识 mspan 等级,包含 class 和 noscan 两部分信息spanclass spanClass // ...
}
Ctz64算法是一种用于计算一个数的二进制表示中尾随零(trailing zeros)的数量的算法
2.2 内存单元等级 spanClass
mspan根据空间大小和面向分配对象的大小,被划分为67种等级,分别是1~67,实际上隐藏的0级用于处理更大的对象
mspan等级列表,<font style="color:rgb(25, 27, 31);">runtime/sizeclasses.go</font>
文件里
- class:mspan等级标识,1~67
- bytes/obj:该大小规格的对象会从这个mspan里获取空间,创建对象过程中,大小会上取整为8B的整数倍,因此该表可以直接实现object到mspan等级的映射
- bytes/span:该等级的mspan的总空间大小
- object:该等级的mspan最多可以new多少个对象,也就是span/obj
- tail waste:span%obj的值
- max waste:当一个对象被分配在某个
size class
中时,由于对象大小与span
大小不完全匹配,可能导致的内存空间未被充分利用的情况
以class 3的 mspan为例,class分配的object大小统一为24B,只有17~24B大小的object会被分配到class3,最坏情况为,object 大小为17B,浪费空间比如为 ((24-17)*341 + 8 ) / 8192 = 28.24%
每个object还有一个重要的属性是nocan,标识了object是否含有指针,在gc时是否需要展开标记。
golang里,把span class 和 nocan两个信息组装为一个uint8,形成完整的spanClass标识。高7位标识span等级,最后一位标识nocan信息。
// A spanClass represents the size class and noscan-ness of a span.
//
// Each size class has a noscan spanClass and a scan spanClass. The
// noscan spanClass contains only noscan objects, which do not contain
// pointers and thus do not need to be scanned by the garbage
// collector.
type spanClass uint8const (numSpanClasses = _NumSizeClasses << 1tinySpanClass = spanClass(tinySizeClass<<1 | 1)
)func makeSpanClass(sizeclass uint8, noscan bool) spanClass {return spanClass(sizeclass<<1) | spanClass(bool2int(noscan))
}func (sc spanClass) sizeclass() int8 {return int8(sc >> 1)
}func (sc spanClass) noscan() bool {return sc&1 != 0
}
2.3 线程缓存mcache
mcache是每个goroutine独有的缓存,因此没有锁。
mcache把每种span class等级的mspan各缓存了一个,并且因为nocan的值也有2种(有指针 无指针),所以总数是2*68=136个
mcache还有一个对象分配器 tiny allocator,用于处理小于16B对象的内存分配。
type mcache struct {_ sys.NotInHeap// The following members are accessed on every malloc,// so they are grouped here for better caching.nextSample uintptr // trigger heap sample after allocating this many bytesscanAlloc uintptr // bytes of scannable heap allocated// Allocator cache for tiny objects w/o pointers.// See "Tiny allocator" comment in malloc.go.// tiny points to the beginning of the current tiny block, or// nil if there is no current tiny block.//// tiny is a heap pointer. Since mcache is in non-GC'd memory,// we handle it by clearing it in releaseAll during mark// termination.//// tinyAllocs is the number of tiny allocations performed// by the P that owns this mcache.tiny uintptrtinyoffset uintptrtinyAllocs uintptr// The rest is not accessed on every malloc.alloc [numSpanClasses]*mspan // spans to allocate from, indexed by spanClassstackcache [_NumStackOrders]stackfreelist// flushGen indicates the sweepgen during which this mcache// was last flushed. If flushGen != mheap_.sweepgen, the spans// in this mcache are stale and need to the flushed so they// can be swept. This is done in acquirep.flushGen atomic.Uint32
}
2.4 中心缓存mcentral
每个mcentral对应一种spanclass,而且聚合了该spanclass下的mspan。
mcentral下的msapn分为2个链表,有空间msapn链表partial和满空间mspan链表full
每个mcentral一把锁
注意partial和full链表都包含两组mspan,一组是已清扫的正在使用的spans,另一组是未清扫的正在使用的spans,在每个垃圾回收GC周期里,这两个角色会互换。
// Central list of free objects of a given size.
type mcentral struct {_ sys.NotInHeapspanclass spanClass// partial and full contain two mspan sets: one of swept in-use// spans, and one of unswept in-use spans. These two trade// roles on each GC cycle. The unswept set is drained either by// allocation or by the background sweeper in every GC cycle,// so only two roles are necessary.//// sweepgen is increased by 2 on each GC cycle, so the swept// spans are in partial[sweepgen/2%2] and the unswept spans are in// partial[1-sweepgen/2%2]. Sweeping pops spans from the// unswept set and pushes spans that are still in-use on the// swept set. Likewise, allocating an in-use span pushes it// on the swept set.//// Some parts of the sweeper can sweep arbitrary spans, and hence// can't remove them from the unswept set, but will add the span// to the appropriate swept list. As a result, the parts of the// sweeper and mcentral that do consume from the unswept list may// encounter swept spans, and these should be ignored.partial [2]spanSet // list of spans with a free objectfull [2]spanSet // list of spans with no free objects
}
2.5 全局堆缓存mheap
堆是操作系统虚拟内存的抽象,以页8KB为单位,其中页是作为最小内存存储单元的。
mheap可以把连续页组装成mspan。
全局内存基于bitMap标识使用情况,每个bit对应一页,为1标识已经被mspan组装。
通过heapArena聚合页,记录了页到mspan的映射信息(详见2.7)
建立空间页基数树索引radix tree index,辅助快速寻找空闲页(详见2.6)
是mcentral的持有者,持有所有spanClass下的mcentral,作为自身的缓存。
内存不够时,向操作系统申请,申请单位是heapArena(64M)
type mheap struct {// 堆的全局锁lock mutex// 空闲页分配器,底层是多棵基数树组成的索引,每棵树对应 16 GB 内存空间pages pageAlloc // 记录了所有的 mspan. 需要知道,所有 mspan 都是经由 mheap,使用连续空闲页组装生成的allspans []*mspan// heapAreana 数组,64 位系统下,二维数组容量为 [1][2^22]// 每个 heapArena 大小 64M,因此理论上,Golang 堆上限为 2^22*64M = 256Tarenas [1 << arenaL1Bits]*[1 << arenaL2Bits]*heapArena// 多个 mcentral,总个数为 spanClass 的个数central [numSpanClasses]struct {mcentral mcentral// 用于内存地址对齐pad [cpu.CacheLinePadSize - unsafe.Sizeof(mcentral{})%cpu.CacheLinePadSize]byte}// ...
}
Golang内存模型和分配机制
相关文章:

Golang内存模型总结1(mspan、mcache、mcentral、mheap)
1.内存模型 1.1 操作系统存储模型 从上到下分别是寄存器、高速缓存、内存、磁盘,其中越往上速度越快,空间越小,价格越高。 关键词是多级模型和动态切换 1.2 虚拟内存与物理内存 虚拟内存是一种内存管理技术,允许计算机使用比…...

lobeChat安装
一、安装Node.js version > v18.17.0 二、下载 cd F:\AITOOLS\LobeChat git clone https://github.com/lobehub/lobe-chat.git (下载要是失败就手动下:https://codeload.github.com/lobehub/lobe-chat/zip/refs/heads/main) npm install …...

Android学习8 -- NDK2--练习2(Opencv)
以下是一个简单的安卓项目示例,通过NDK调用OpenCV来处理图像(例如,将彩色图像转换为灰度图像)。 开发环境 安装 Android Studio(支持NDK开发)。配置NDK和CMake(通过Android Studio的SDK Manage…...

nodejs循环导出多个word表格文档
文章目录 nodejs循环导出多个word表格文档一、文档模板编辑二、安装依赖三、创建导出工具类exportWord.js四、调用五、效果图nodejs循环导出多个word表格文档 结果案例: 一、文档模板编辑 二、安装依赖 // 实现word下载的主要依赖 npm install docxtemplater pizzip --save/…...

elasticsearch-如何给文档新增/更新的字段
文章目录 前言elasticsearch-如何给文档新增/更新的字段1. 如何给某些文档新增/更新的字段2. 给所有文档添加/更新一个新的字段3. 测试 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且…...

https/http访问接口工具类,附带ssl忽略证书验证,以及head头部的添加-java版
复制即用 package utils;import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import javax.net.ssl.*; import java.io.BufferedReader; import java.io.IOException; impo…...

node.js基础学习-express框架-静态资源中间件express.static(十一)
前言 在 Node.js 应用中,静态资源是指那些不需要服务器动态处理,直接发送给客户端的文件。常见的静态资源包括 HTML 文件、CSS 样式表、JavaScript 脚本、图片(如 JPEG、PNG 等)、字体文件和音频、视频文件等。这些文件在服务器端…...

Python语法基础---正则表达式
🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 我们这个文章所讲述的,也是数据分析的基础文章,正则表达式 首先,我们在开始之前,引出一个问题。也是我们接下来想要解决的问题。…...

Uniapp 微信小程序分享 - 自定义绘制分享图片
技术栈: Uniapp Vue3 简介 因实际业务需求,需要实现微信小程序自定义分享,根据当前数据动态生成(绘制)分享卡片的图片。 基础分享使用 配置此处不在赘述,可查看上篇博客:Uniapp 微信小程序分…...

鸿蒙技术分享:Navigation页面容器封装-鸿蒙@fw/router框架源码解析(三)
本文是系列文章,其他文章见:鸿蒙fw/router框架源码解析(一)-router页面管理鸿蒙fw/router框架源码解析(二)-Navigation页面管理鸿蒙fw/router框架源码解析(四)-路由Hvigor插件实现原…...

三步入门Log4J 的使用
本篇基于Maven 的Project项目, 快速演示Log4j 的导入和演示。 第一步: 导入Log4j依赖 <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.24.2</version&…...

VBA中类的解读及应用第十八讲:利用类方法,判断任意单元格类型
《VBA中类的解读及应用》教程【10165646】是我推出的第五套教程,目前已经是第一版修订了。这套教程定位于最高级,是学完初级,中级后的教程。 类,是非常抽象的,更具研究的价值。随着我们学习、应用VBA的深入࿰…...

查询品牌涉及两张表(brand、brand_admin_mapping)
文章目录 1、BrandController2、AdminCommonService3、BrandApiService3、BrandCommonService4、BrandSqlService涉及的表SQL 查询逻辑参数处理执行查询完整 SQL 逻辑参数映射总结 查询指定管理员下的品牌所涉及的表有哪些? http://127.0.0.1:8087/brand/admin/list…...

Eureka和Zookeeper、Nacos的区别
目录 一、Eureka与Zookeeper的区别 适用场景: 架构设计: 功能特性: 社区生态: 二、Eureka与Nacos的区别 接口方式: 实例类型: 健康检测: 服务发现: 一致性与可用性&#…...

微信小程序怎么实现非tabbar页面显示tabbar,自定义组件实现
微信小程序没有发现可以实现非tabbar页面显示tabbar的方法,但是可以在tabbar页面当中隐藏tabbar,使用wx.hideTabBar()方法就可以实现,在非tabbar页面调用wx.showTabBar()方法却会显示失败,不能显示tabbar onLoad() {wx.showTabBar…...

SpringBoot如何使用EasyExcel实现表格导出(简洁快速入门版本)
前言 前面给大家介绍了动态表头的导入,这篇文章给大家介绍如何实现导出 前面给大家介绍了动态表头的导入,我们了解了如何通过EasyExcel灵活地读取结构不固定的Excel文件。这次,我们将目光转向数据导出——即如何将数据以Excel文件的形式输出…...

多种平台上安装部署调试Open5GS(四)
OpenWRT 源码安装 UERANSIM 安装依赖openwrt源码安装cmake其他依赖准备UERANSIM安装测试验证Open5GS 是一个功能完善的开源5G项目,具备5G、4G核心网功能,最新代码支持R17标准, 本系列文章介绍Open5GS在x86、ARM平台上的安装部署方法,并通过搭建UERANSIN、商用5G基站和终端两…...

单片机的基本构成与工作原理
单片机,即微控制器(Microcontroller Unit,MCU),是一种将中央处理器(CPU)、存储器(ROM/RAM)、定时/计数器(Timer/Counter)、中断系统、输入输出(I/O)接口等集成在一块芯片上的微型计算机。它具有体积小、功耗低、成本低…...

opencv常用图像处理操作
OpenCV 处理图像的通用流程通常包括以下几个步骤,根据具体需求可以调整或跳过某些步骤。以下是一个通用的框架: 读取图像 加载图像文件到内存中以进行后续处理。 import cv2 读取图像 image cv2.imread(‘image.jpg’) # 彩色图像 gray_image cv2…...

Svn如何切换删除账号
记录Svn清除切换账号 1.首先打开小乌龟的设置如下图 打开设置后单击已保存数据,然后选择清除 接上图选择清除后,就可以打勾选择清除已保存的账号,我们再次检出的就可以切换账号了 👉总结 本次记录Svn清除切换账号 如能帮助到你…...

使用PaddleOCR遇到的问题Bug
Q1: 训练模型的预测效果比inference模型的预测效果差距很大,怎么办?原因是什么? A1: 训练模型:使用训练数据集进行训练后的模型。 inference模型:把模型结构和模型参数保存在文件中的固化模型,多用于预测部署场景。训练过程中保存的模型是checkpoints模型,保存的只有模…...

了解Xcode在iOS开发中的作用和功能有哪些
Xcode是什么?它在iOS开发中的作用和功能有哪些? 一、Xcode是什么? Xcode是苹果公司针对macOS平台开发的一款集成开发环境(Integrated Development Environment,简称IDE)。它主要用于开发iOS、iPadOS、mac…...

《船舶物资与市场》是什么级别的期刊?是正规期刊吗?能评职称吗?
问题解答 问:《船舶物资与市场》是不是核心期刊? 答:不是,是知网收录的正规学术期刊。 问:《船舶物资与市场》级别? 答:国家级。主管单位:中国船舶集团有限公司 主办单…...

商汤完成组织架构调整,改革完成的商汤未来何在?
首先,从核心业务的角度来看,商汤科技通过新架构明确了以AI云、通用视觉模型等为核心业务的战略方向。这一举措有助于商汤科技集中资源,加强在核心业务领域的研发和市场拓展,提高市场竞争力。同时,坚定生成式AI为代表的…...

MyBatis异常体系中ErrorContext和ExceptionFactory原理分析
🎮 作者主页:点击 🎁 完整专栏和代码:点击 🏡 博客主页:点击 文章目录 exceptions包分包设计ExceptionFactory类介绍为什么使用工厂不是直接new呢?【统一的异常处理机制】【异常的封装与转化】【…...

WHLUG丨deepin、华中科技大学开放原子开源俱乐部、 RustSBI 和清华大学开源操作系统训练营共话开源新生代成长之路
2024年11月30日下午,由 deepin(深度)社区联合华中科技大学开放原子开源俱乐部、 RustSBI 开源社区和清华大学开源操作系统训练营共同举办的WHLUG(武汉Linux用户组)线下沙龙在华中科技大学成功举办。 本次活动聚集了50余…...

通过HTML Canvas 在图片上绘制文字
目录 前言 一、HTML Canvas 简介 二、准备工作 三、绘制图片 四、绘制文字 五、完整代码 效果演示: 前言 HTML canvas 为我们提供了无限的创意可能性。今天,我们就来探索一下如何通过 HTML canvas 将图片和文字绘制到图片上,创造出独特…...

C# 冒泡的算法
C# 冒泡的算法 public void BubbleSort(int[] arr) {int temp;for (int j 0; j < arr.Length - 2; j){for (int i 0; i < arr.Length - 2; i){if (arr[i] > arr[i 1]){temp arr[i 1];arr[i 1] arr[i];arr[i] temp;}}} }使用方法 int[] array new int[] { 5,…...

大数据项目-Django基于聚类算法实现的房屋售房数据分析及可视化系统
《[含文档PPT源码等]精品Django基于聚类算法实现的房屋售房数据分析及可视化系统》该项目含有源码、文档、PPT、配套开发软件、软件安装教程课程答疑等! 数据库管理工具:phpstudy/Navicat或者phpstudy/sqlyog 后台管理系统涉及技术: 后台使…...

AWS创建ec2实例并连接成功
aws创建ec2实例并连接 aws创建ec2并连接 1.ec2创建前准备 首先创建一个VPC隔离云资源并且有公有子网 2.创建EC2实例 1.启动新实例或者创建实例 2.创建实例名 3.选择AMI使用linux(HVM) 4.选择实例类型 5.创建密钥对下载到本地并填入密钥对名称 6.选择自己创建的VPC和公有子网…...