当前位置: 首页 > news >正文

Golang内存模型总结1(mspan、mcache、mcentral、mheap)

1.内存模型

1.1 操作系统存储模型

从上到下分别是寄存器、高速缓存、内存、磁盘,其中越往上速度越快,空间越小,价格越高。

关键词是多级模型和动态切换

1.2 虚拟内存与物理内存

虚拟内存是一种内存管理技术,允许计算机使用比物理内存更多的内存资源,通过将部分内存存储在硬盘上的方式,扩展了系统的可用内存。

1.3 分页管理

操作系统会把虚拟内存和物理内存切割成固定的尺寸,于虚拟内存而言叫做“页”,于物理内存而言叫“帧”,原因如下:

  • 提高内存空间利用,减少外部碎片,内部碎片相对可控
  • 提高内外存交换的效率,更细的粒度带来了更高的灵活度
  • 与虚拟内存机制呼应,便于使用页表建立虚拟地址到物理地址之间的映射
  • linux 页/帧的大小固定为4KB,实践得到的经验值,太大的话会增加碎片率,太小的话增加分配频率影响效率

1.4 Golang内存模型

几个核心的设计要点:

  1. 空间换时间,一次缓存,多次复用:因为每次向操作系统申请内存的操作很重,那么不妨一次多申请一些,以备后用。Golang的堆mheap正是基于该思想产生的数据结构,对于操作系统而言,这是用户进程中缓存的内存;对于Go进程内部,堆是所有对象的内存起源。
  2. 多级缓存,实现无/细锁化:堆是Go运行时最大的临界共享资源,这意味着每次存取都要加锁,很影响性能。为了解决这个问题,Golang依次细化粒度,建立了mcentral,mcache的模型:
    1. mheap:全局的内存起源,访问要加全局锁。数量只有1个
    2. mcentral:每种对象大小规格对应的缓存,锁的粒度仅仅局限于同一种规格里,全局划分为68份。(BigCache也用到了类似的思想)数量有68*2个(详细见2.3)
    3. mcache:每个P(即goroutine 内核线程)持有的一份内存缓存,访问时没有锁。数量等于P的数量
  3. 多级规格,提高利用率
    1. page:最小的存储单元,借鉴操作系统分页管理的思想,每个最小的存储单元也称之为页,但是大小为8KB
    2. mspan:最小的管理单元,大小是page的整数倍,从8B到80KB被划分为67种不同的规格,分配对象时,会根据大小映射到不同规则的mspan,从中获取空间。产生的特点
      1. 根据规格大小,产生了等级的制度,才使得central支持细锁化
      2. 消除了外部碎片,但是不可避免地会有内部碎片
      3. 宏观上能提高整体空间利用率

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 操作系统存储模型 从上到下分别是寄存器、高速缓存、内存、磁盘&#xff0c;其中越往上速度越快&#xff0c;空间越小&#xff0c;价格越高。 关键词是多级模型和动态切换 1.2 虚拟内存与物理内存 虚拟内存是一种内存管理技术&#xff0c;允许计算机使用比…...

lobeChat安装

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

Android学习8 -- NDK2--练习2(Opencv)

以下是一个简单的安卓项目示例&#xff0c;通过NDK调用OpenCV来处理图像&#xff08;例如&#xff0c;将彩色图像转换为灰度图像&#xff09;。 开发环境 安装 Android Studio&#xff08;支持NDK开发&#xff09;。配置NDK和CMake&#xff08;通过Android Studio的SDK Manage…...

nodejs循环导出多个word表格文档

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

elasticsearch-如何给文档新增/更新的字段

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

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 应用中&#xff0c;静态资源是指那些不需要服务器动态处理&#xff0c;直接发送给客户端的文件。常见的静态资源包括 HTML 文件、CSS 样式表、JavaScript 脚本、图片&#xff08;如 JPEG、PNG 等&#xff09;、字体文件和音频、视频文件等。这些文件在服务器端…...

Python语法基础---正则表达式

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

Uniapp 微信小程序分享 - 自定义绘制分享图片

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

鸿蒙技术分享:Navigation页面容器封装-鸿蒙@fw/router框架源码解析(三)

本文是系列文章&#xff0c;其他文章见&#xff1a;鸿蒙fw/router框架源码解析&#xff08;一&#xff09;-router页面管理鸿蒙fw/router框架源码解析&#xff08;二&#xff09;-Navigation页面管理鸿蒙fw/router框架源码解析&#xff08;四&#xff09;-路由Hvigor插件实现原…...

三步入门Log4J 的使用

本篇基于Maven 的Project项目&#xff0c; 快速演示Log4j 的导入和演示。 第一步&#xff1a; 导入Log4j依赖 <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.24.2</version&…...

VBA中类的解读及应用第十八讲:利用类方法,判断任意单元格类型

《VBA中类的解读及应用》教程【10165646】是我推出的第五套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。 类&#xff0c;是非常抽象的&#xff0c;更具研究的价值。随着我们学习、应用VBA的深入&#xff0…...

查询品牌涉及两张表(brand、brand_admin_mapping)

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

Eureka和Zookeeper、Nacos的区别

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

微信小程序怎么实现非tabbar页面显示tabbar,自定义组件实现

微信小程序没有发现可以实现非tabbar页面显示tabbar的方法&#xff0c;但是可以在tabbar页面当中隐藏tabbar&#xff0c;使用wx.hideTabBar()方法就可以实现&#xff0c;在非tabbar页面调用wx.showTabBar()方法却会显示失败&#xff0c;不能显示tabbar onLoad() {wx.showTabBar…...

SpringBoot如何使用EasyExcel实现表格导出(简洁快速入门版本)

前言 前面给大家介绍了动态表头的导入&#xff0c;这篇文章给大家介绍如何实现导出 前面给大家介绍了动态表头的导入&#xff0c;我们了解了如何通过EasyExcel灵活地读取结构不固定的Excel文件。这次&#xff0c;我们将目光转向数据导出——即如何将数据以Excel文件的形式输出…...

多种平台上安装部署调试Open5GS(四)

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

单片机的基本构成与工作原理

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

opencv常用图像处理操作

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

Svn如何切换删除账号

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

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...