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内存模型和分配机制

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET Core8.0学习笔记(二十五)——EF Core Include导航数据加载之预加载与过滤

一、导航属性数据加载 1.在EF Core中可以使用导航属性来加载相关实体。 2.加载实体的三种方式&#xff1a; (1)预先加载&#xff1a;直接在查询主体时就把对应的依赖实体查出来&#xff08;作为初始查询的一部分&#xff09; (2)显式加载&#xff1a;使用代码指示稍后显式的从…

MATLAB Simulink® - 智能分拣系统

系列文章目录 前言 本示例展示了如何在虚幻引擎 环境中对四种不同形状的标准 PVC 管件实施半结构化智能分拣。本示例使用 Universal Robots UR5e cobot 执行垃圾箱拣选任务&#xff0c;从而成功检测并分类物体。cobot 的末端执行器是一个吸力抓手&#xff0c;它使 cobot 能够拾…

环形链表 (简单易懂)

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…

【C++】奇偶数判断题的高级分析与优化

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;1. 题目描述题目背景 &#x1f4af;2. 基本解决思路示例分析 &#x1f4af;3. 原始代码分析代码分析代码优点代码缺点 &#x1f4af;4. 教师代码及其优化分析代码分析代码优…

1.1 Beginner Level学习之“创建 ROS msg 和 srv”(第十节)

学习大纲&#xff1a; 1. msg 和 srv msg 文件是描述 ROS 消息字段的简单文本文件。它们用于为不同语言生成消息的源代码。srv 文件则描述了一个服务&#xff0c;包括两部分&#xff1a;请求和响应。Srv 文件用于生成服务的源代码。msg 文件存储在包的 msg 目录中。srv 文件存…

Linux-笔记---系统文件I/O

1. open函数和close函数 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);#include <unistd.h> int close(int fd); open函数…

红日靶场vulnstark 4靶机的测试报告[细节](一)

目录 一、测试环境 1、系统环境 2、注意事项 3、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、漏洞利用Getshell ①Struts 2 s2-045漏洞 手工利用s2-45漏洞 Msf综合利用 ②Tomcat框架(CVE-2017-12615) ③phpMyAdmin(CVE-2018-12613) 构造语句写入冰蝎木…

利用 360 安全卫士极速版关闭电脑开机自启动软件教程

在使用电脑的过程中&#xff0c;过多的开机自启动软件会严重拖慢电脑的开机速度&#xff0c;影响我们的使用体验。本教程中简鹿办公将详细介绍如何使用 360 安全卫士极速版关闭电脑开机自启动软件&#xff0c;让您的电脑开机更加迅速流畅。 一、打开 360 安全卫士极速版 在电…

计算机毕业设计Spark股票推荐系统 股票预测系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

本文介绍麒麟信安服务器系统(kylinsec)的安装。

本文介绍麒麟信安服务器系统&#xff08;kylinsec&#xff09;的安装。 下载 在开源欧拉官方找到商业版本的介绍找到相关产品&#xff1a; https://www.openeuler.org/zh/download/commercial-release/ 麒麟信安kylinsec下载地址&#xff1a; https://mirrors.kylinsec.com…

并发专题(10)之FutureTask源码剖析

一、FutureTask介绍 Java创建线程的方式&#xff0c;一般常用的是Thread&#xff0c;Runnable&#xff0c;如果需要处理当前的任务有返回结果的话&#xff0c;需要使用Callable。Callable运行需要配合Future来使用。 Future是一个接口&#xff0c;一般会使用FutureTask实现类去…

ssh远程升级Ubuntu20.04到Ubuntu 22.04

ssh远程升级Ubuntu20.04到Ubuntu 22.04 陈拓 2024/10/16-2024/10/26 1. 简介 本文介绍了如何通过ssh将Ubuntu系统从20.04升级到22.04。 在进行系统升级之前&#xff0c;建议备份重要数据&#xff0c;以防升级过程中出现问题。 2. 更新当前系统 硬件系统架构 当前操作系统版…

新手SEO指南:如何从零开始优化网站实现流量增长

内容概要 在这一部分&#xff0c;我们将简要概述新手在进行SEO优化时需要掌握的一些关键内容。SEO&#xff08;搜索引擎优化&#xff09;是一个复杂而多层次的过程&#xff0c;对网站流量的提升至关重要。无论您是刚刚踏入这一领域的新手&#xff0c;还是希望进一步提升网站性…

FPGA实战篇(呼吸灯实验)

1.呼吸灯简介 呼吸灯采用 PWM 的方式&#xff0c;在固定的频率下&#xff0c;通过调整占空比的方式来控制 LED 灯亮度的变化。 PWM&#xff08;Pulse Width Modulation &#xff09;&#xff0c;即脉冲宽度调制&#xff0c;它利用微处理器输出的 PWM 信号&#xff0c;实现对…

使用 OpenCV 进行 Android 开发

在本节中&#xff0c;我们将创建一个简单的应用程序&#xff0c;它除了加载 OpenCV 之外什么都不做。在下一节中&#xff0c;我们将扩展它以支持相机。 除了这个说明&#xff0c;你还可以使用一些视频指南&#xff0c;例如这个 打开 Android Studio 并选择Empty Views Activi…

项目实例_FashionMNIST_CNN

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…

Autosar FO时间分析和设计规范导读

一、规范功能概述 “Timing Analysis and Design AUTOSAR FO R24 - 11” 文档主要聚焦于汽车电子系统开发中的定时分析与设计&#xff0c;详细阐述了相关概念、方法、用例及涉及的各项要素&#xff0c;旨在为汽车电子系统的开发提供全面且系统的定时分析指导&#xff0c;以确保…

使用 libssh2_session_set_timeout 设置 SSH 会话超时时间

使用 libssh2_session_set_timeout 设置 SSH 会话超时时间 函数原型参数说明返回值示例代码注意事项libssh2_session_set_timeout 是 libssh2 库中的一个函数,用于设置 SSH 会话的超时时间。这对于防止网络延迟或连接中断导致的长时间挂起非常有用。 函数原型 int libssh2_se…

001 LVGL PC端模拟搭建

01 LVGL模拟器介绍 使用PC端软件模拟LVGL运行&#xff0c;而不需要任何嵌入式硬件 环境搭建&#xff1a;codeblocks-20.03mingw-setup 正常安装流程即可 工程获取&#xff1a;LVGL官网-> github仓库 本地安装包下载资源包 工程模版和软件安装包 补充&#xff1a;…

开源ISP介绍(2)————嵌入式Vitis搭建

Vivado搭建参考前一节Vivado基于IP核的视频处理框架搭建&#xff1a; 开源ISP介绍&#xff08;1&#xff09;——开源ISP的Vivado框架搭建-CSDN博客 导出Hardware 在vivado中导出Hardware文件&#xff0c;成功综合—实现—生成比特流后导出硬件.xsa文件。&#xff08;注意导…