Golang内存模型与分配机制

news2024/11/26 16:42:00

简述

在这里插入图片描述
mheap为堆,堆和进程是一对一的;mcentral(小mheadp),mcahe(GMP的P私有),分配内存顺序由后向前。
在解决这个问题,Golang 在堆 mheap 之上,依次细化粒度,建立了mcentral、mcache 的模型,下面对三者作个梳理:

  • mheap:全局的内存起源,访问要加全局锁
  • mcentral:每种对象大小规格(全局共划分为68种)对应的缓存,锁的粒度也仅限于同一种规格以内
  • mcache:每个P(正是GMP中的P)持有一份的内存缓存,访问时无锁
    在这里插入图片描述
    首先理下page和mspan两个概念∶
    (1) page:最小的存储单元.
    Golang 借鉴操作系统分页管理的思想,每个最小的存储单元也称之为页page,但大小为8 KB
    (2) mspan:最小的管理单元.
    mspan 大小为 page 的整数倍,且8B到80 KB被划分为67种不同的规格,分配对象时,会根据大小映射到不同规格的mspan,从中获取空间.
    于是,我们回头小节多规格mspan下产生的特点︰
  • 根据规格大小,产生了等级的制度
  • 消除了外部碎片,但不可避免会有内部碎片
  • 宏观上能提高整体空间利用率
  • 正是因为有了规格等级的概念,才支持mcentral实现细锁化

核心概念梳理

内存单元mspan

在这里插入图片描述
分点阐述mspan的特质:

  • mspan是Golang内存管理的最小单元
  • mspan大小是page的整数倍(Go 中的page 大小为8KB),且内部的页是连续的(至少在虚拟内存的视角中是这样)
  • 每个mspan根据空间大小以及面向分配对象的大小,会被划分为不同的等级
  • 同等级的mspan 会从属同一个mcentral,最终会被组织成链表,因此带有前后指针((prev、next)·- 由于同等级的mspan内聚于同一个mcentral,所以会基于同一把互斥锁管理
  • mspan 会基于bitMap辅助快速找到空闲内存块(块大小为对应等级下的object大小),此时需要使用到Ctz64算法.
    在这里插入图片描述
    在这里插入图片描述

内存单元等级spanClass

mspan根据空间大小和面向分配对象的大小,被划分为67种等级(1-67,实际上还有一种隐藏的0级,用于处理更大的对象,上不封顶)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
除了上面谈及的根据大小确定的mspan等级外,每个object还有一个重要的属性叫做nocan,标识了object是否包含指针,在gc时是否需要展开标记.
在Golang 中,会将span class + nocan两部分信息组装成一个uint8,形成完整的
spanClass 标识.8个 bit中,高7位表示了上表的span等级((总共67+1个等级,8个bit足够用了),最低位表示nocan信息.
在这里插入图片描述

线程缓存mcache

在这里插入图片描述
(1) mcache是每个Р独有的缓存,因此交互无锁
(2) mcache 将每种spanClass 等级的mspan各缓存了一个,总数为2 (nocan维度)*68(大小维度)=136
(3) mcache 中还有一个为对象分配器tiny allocator,用于处理小于16B对象的内存分配
在这里插入图片描述

中心缓存mcentral

在这里插入图片描述
要点∶
(1)每个mcentral对应一种spanClass
(2)每个mcentral 下聚合了该spanClass 下的mspan
(3) mcentral 下的mspan分为两个链表,分别为有空间mspan链表partial和满空间mspan链表full
(4)每个mcentral一把锁
在这里插入图片描述

全局堆缓存mheap

要点

  • 对于Golang上层应用而言,堆是操作系统虚拟内存的抽象·
  • 以页(8KB)为单位,作为最小内存存储单元
  • 负责将连续页组装成mspan
  • 全局内存基于bitMap标识其使用情况,每个bit对应一页,为0则自由,为1则已被mspan组装·
  • 通过heapArena 聚合页,记录了页到mspan的映射信息
  • 建立空闲页基数树索引 radix tree index,辅助快速寻找空闲页
  • 是mcentral 的持有者,持有所有spanClass 下的mcentral,作为自身的缓存
  • 内存不够时,向操作系统申请,申请单位为heapArena (64M)
    在这里插入图片描述

空闲也索引pageAlloc

数据结构背后的含义:

  • mheap 会基于bitMap标识内存中各页的使用情况,bit位为0代表该页是空闲的,为1代表该页已被mspan占用.
    • 每棵基数树聚合了16 GB内存空间中各页使用情况的索引信息,用于帮助 mheap快速找到指定长度的连续空闲页的所在位置
  • mheap持有214 棵基数树,因此索引全面覆盖到 214*16 GB = 256 T的内存空间.

在这里插入图片描述

  • 每个父 pallocSum有8个子pallocSum
  • 根pallocSum总览全局,映射的 bitMap范围为全局的16 GB空间(其max最大值为221,因此总空间大小为221*8KB=16GB) ;
  • 从首层向下是一个依次八等分的过程,每一个pallocSum映射其父节点bitMap范围的八分之一,因此第二层pallocSum的 bitMap 范围为16GB/8 = 2GB,以此类推,第五层节点的范围为16GB /(84) = 4 MB,已经很小
  • 聚合信息时,自底向上.每个父pallocSum聚合8个子pallocSum的start、max、end信息,形成自己的信息,直到根pallocSum,坐拥全局16 GB的start、max、end 信息
  • mheap寻页时,自顶向下.对于遍历到的每个pallocSum,先看起start 是否符合,是则寻页成功;再看max是否符合,是则进入其下层孩子pallocSum中进一步寻访;最后看end和下一个同辈pallocSum 的start聚合后是否满足,是则寻页成功.

每层节点
在这里插入图片描述
基数树中,每个节点称之为PallocSum,是一个uint64类型,体现了索引的聚合信息,包含以下四部分:

  • start:最右侧21个bit,标识了当前节点映射的 bitMap 范围中首端有多少个连续的0 bit(空闲页),称之为start;
  • max:中间21个bit,标识了当前节点映射的 bitMap范围中最多有多少个连续的0 bit(空闲页),称之为max;
  • end:左侧21个 bit,标识了当前节点映射的 bitMap范围中最末端有多少个连续的0 bit(空闲页),称之为end.
  • 最左侧一个bit,弃置不用
    在这里插入图片描述
    基数树节点
    在这里插入图片描述
    在这里插入图片描述

heapArena

  • 每个heapArena包含8192个页,大小为8192* 8KB = 64 MB
  • **heapArena记录了页到msplan的映射.**因为GC时,通过地址偏移找到页很方便,但找到其所属的mspan不容易.因此需要通过这个映射信息进行辅助.
  • heapArena是mheap向操作系统申请内存的单位(64MB)
    在这里插入图片描述

对象分配流程

下面来串联 Golang中分配对象的流程,不论是以下哪种方式,最终都会殊途同归步入mallocgc方法中,并且根据3.1小节中的策略执行分配流程:

  • new(T)
  • &T{}
  • make(xxxx)

分配流程总览

Golang中,依据 object的大小,会将其分为下述三类∶

  • tiny微对象(0-16B)
  • small小对象(16B-32KB)
  • large大对象(32KB—)

不同类型的对象,会有着不同的分配策略,这些内容在mallocgc方法中都有体现.
核心流程类似于读多级缓存的过程,由上而下,每一步只要成功则直接返回.若失败,则由下层方法兜底.

对于微对象的分配流程︰

(1)从P专属mcache 的tiny 分配器取内存(无锁)
(2)根据所属的spanClass,从Р专属mcache 缓存的mspan中取内存(无锁)
(3)根据所属的spanClass 从对应的mcentral中取 mspan填充到mcache,然后从mspan中取内存(spanclass粒度锁)
(4)根据所属的spanClass,从 mheap 的页分配器 pageAlloc取得足够数量空闲页组装成mspan填充到mcache,然后从mspan中取内存(全局锁)
(5) mheap向操作系统申请内存,更新页分配器的索引信息,然后重复(4) .

对于小对象的分配流程是跳过〔1)步,执行上述流程的(2) - (5)步;

对于大对象的分配流程是跳过(1)-(3)步,执行上述流程的(4) - (5)步.

主干方法,mallocgc

微对象分配
在这里插入图片描述
在这里插入图片描述
小对象分配
在这里插入图片描述
大对象分配
在这里插入图片描述

tiny分配

每个Р独有的mache 会有个微对象分配器,基于 offset线性移动的方式对微对象进行分配,每16B成块,对象依据其大小,会向上取整为2的整数次幂进行空间补齐,然后进入分配流程.
在这里插入图片描述
在这里插入图片描述

mcache分配

在这里插入图片描述
在mspan中,基于Ctz64算法,根据 mspan.allocCache 的 bitMap信息快速检索到空闲的object块,进行返回.
在这里插入图片描述

mcentral分配

当mspan无可用的object内存块时,会步入mcache.nextFree方法进行兜底.
在这里插入图片描述
在这里插入图片描述
mcentral.cacheSpan方法中,会加锁(spanClass 级别的sweepLocker),分别从 partial和full中尝试获取有空间的mspan:
在这里插入图片描述

mheap分配

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

操作系统申请

倘若mheap中没有足够多的空闲页了,会发起mmap系统调用,向操作系统申请额外的内存空间.
在这里插入图片描述
在这里插入图片描述

基数树寻页

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

SQL注入-上篇

SQL注入 注入是web安全的头号大敌。注入攻击漏洞往往是应用程序缺少对输入进行安全性检查所引起的。攻击者把一些包含攻击代码当做命令或者查询语句发送给解释器,这些恶意数据可以欺骗解释器,从而执行计划外的命令或者未授权访问数据。注入漏洞通常能sq…

AI + 3D:用单个图像和文本提示创建可交互的3D世界

你是否曾经梦想过只需一张照片和一些简单的文字描述,就能立即进入一个生动的3D虚拟世界?今天,我们将介绍一个革命性的技术,它就像是一台神奇的3D场景制造机,能够根据你的想象快速构建出令人惊叹的虚拟空间。 一、技术概览 这项技术不仅仅是一个简单的图像到3D的转换工具…

线程池吞掉异常的case:源码阅读与解决方法

1. 问题背景 有一天给同事CR,看到一段这样的代码 try {for (param : params) {//并发处理,func无返回值ThreadPool.submit(func(param));} } catch (Exception e) {log.info("func抛异常啦,参数是:{}", param) } 我:你这段代码是…

函数式编程基本语法

文章目录 1.函数对象表现形式1.Lambda表达式(功能全面)1.基本语法2.只有一行逻辑,该逻辑结果是返回值3.复杂逻辑4.省略参数类型(可以通过上下文推导出类型时,比如实现了函数式接口)5.只有一个参数时&#x…

SQL160 国庆期间每类视频点赞量和转发量

描述 用户-视频互动表tb_user_video_log iduidvideo_idstart_timeend_timeif_followif_likeif_retweetcomment_id110120012021-09-24 10:00:002021-09-24 10:00:20110NULL210520022021-09-25 11:00:002021-09-25 11:00:30001NULL310220022021-09-25 11:00:002021-09-25 11:00…

【数据结构】红黑树实现详解

在本篇博客中,作者将会带领你使用C来实现一棵红黑树,此红黑树的实现是基于二叉搜索树和AVLTree一块来讲的,所以在看本篇博客之前,你可以先看看下面这两篇博客 【C】二叉搜索树-CSDN博客 【数据结构】AVLTree实现详解-CSDN博客 在这…

21.FuturePromise

在异步处理时,经常用到两个接口Future 和 Promise。 说明:Netty中的Future与jdk中的Future同名,但是是两个接口,netty的Future继承了jdk的Future,而Promise又对Netty的Future进行了扩展。 JDK的Future只能同步等待任务结束(成功、失败)才能得到结果。FutureTask.get()方…

项目(一)--高并发内存池项目简介

什么是高并发内存池 它是一个全球性大厂google(谷歌)的 开源项目,项目名字叫tcmalloc,全称是Thread-Caching Malloc,即线程缓存的malloc 作用: 我们知道C语言在堆上开辟空间和 释放使用的是malloc和free函数 并且C的动态内存管理new和delete 的底层实际上也调用了…

高考志愿填报:选择好专业还是好学校?

人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 高考志愿填报:选择好专业还是好学校? 每年高考结束后,考生和家长面临的一个…

数据结构之线性表(3)

数据结构之线性表(3) 上文我们了解了线性表的静动态存储的相关操作,此篇我们对线性表中链表的相关操作探讨。 在进行链表的相关操作时,我们先来理解单链表是什么? 1.链表的概念及结构 链表是一种物理存储结构上非连…

密钥管理简介

首先我们要知道什么是密钥管理? 密钥管理是一种涉及生成、存储、使用和更新密钥的过程。 密钥的种类 我们知道,对称密码主要包括分组密码和序列密码。但有时也可以将杂凑函数和消息认证码划分为这一类,将它们的密钥称为对称密钥;…

RAG与Langchain简介

RAG与Langchain简介 什么是RAGRAG解决的问题RAG工作流程RAG调优策略LangChain简介 什么是RAG 检索增强生成(Retrieval-Augmented Generation),主要是通过从外部给大模型补充一些知识,相当于给模型外挂了一个知识库,让…

Navicat 安装及初步配置指南

Navicat 是一款广泛使用的数据库管理工具,支持多种数据库,如 MySQL、PostgreSQL、SQLite 等。以下是 Navicat 安装步骤的详细说明: 在 Windows 上安装 Navicat 下载 Navicat 安装包: 访问 Navicat 官方网站:Navicat 官…

iCopy for Mac 剪切板 粘贴工具 历史记录 安装(保姆级教程,新手小白轻松上手)

Mac分享吧 文章目录 效果可留存文本、图片、文件等复制历史记录也可根据关键字进行历史记录检索点击一下,可复制双击两下,复制内容,并将信息粘贴至鼠标指针处 一、准备工作二、开始安装1、双击运行软件,将其从左侧拖入右侧文件夹…

【Vue】Pinia管理用户数据

Pinia管理用户数据 基本思想:Pinia负责用户数据相关的state和action,组件中只负责触发action函数并传递参数 步骤1:创建userStore 1-创建store/userStore.js import { loginAPI } from /apis/user export const useUserStore defineStore(…

Havoc工具

Team端 客户端 打开后需要生成监听器和agent 监听 生成payload 最后上线 HTTPS流量 HTTP流量 心跳

基于微信小程序的在线答题小程序设计与实现

个人介绍 hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的…

安装 Nuxt.js 的步骤和注意事项

title: 安装 Nuxt.js 的步骤和注意事项 date: 2024/6/17 updated: 2024/6/17 author: cmdragon excerpt: Nuxt.js在Vue.js基础上提供的服务器端渲染框架优势,包括提高开发效率、代码维护性和应用性能。指南详细说明了从环境准备、Nuxt.js安装配置到进阶部署技巧&…

大模型KV Cache节省神器MLA学习笔记(包含推理时的矩阵吸收分析)

首先,本文回顾了MHA的计算方式以及KV Cache的原理,然后深入到了DeepSeek V2的MLA的原理介绍,同时对MLA节省的KV Cache比例做了详细的计算解读。接着,带着对原理的理解理清了HuggingFace MLA的全部实现,每行代码都去对应…

dentacare - hackmyvm

简介 靶机名称:dentacare 难度:中等 靶场地址:https://hackmyvm.eu/machines/machine.php?vmdentacare 本地环境 虚拟机:vitual box 靶场IP(dentacare):192.168.56.120 跳板机IP(window…