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

Go语言内存分配源码分析学习笔记

大家好,我是V 哥。GO GO GO,今天来说一说Go语言内存分配问题,Go语言内存分配的源码主要集中在runtime包中,它实现了Go语言的内存管理,包括初始化、分配、回收和释放等。下面来对这些过程详细分析一下,先赞后看,绝不摆烂:

1. 内存管理初始化

源码位置: runtime/malloc.go

关键点:

  • mheap初始化:
    • mheap是整个Go运行时的核心内存分配结构,用于管理大块内存。
    • 初始化时,Go会从操作系统中获取一大块内存作为堆空间,通过sysAlloc分配给mheap
  func mallocinit() {mheap_.init() // 初始化全局mheap_}
  • mcache初始化:
    • 每个P(逻辑处理器)有一个mcache,用来缓存小块内存分配,减少锁竞争。
    • mcachemheap分配,存储小块内存(≤32KB)。
  func allocmcache() *mcache {c := new(mcache)c.refill() // 预填充小内存块return c}

2. 内存分配

Go的内存分配分为以下几种场景:

2.1 小对象分配(≤32KB)

  • 使用mcache中的内存。
  • mcache按大小类(class)分配,这些类通过sizeclasses数组定义。
  • 分配时,调用mcache.alloc,如果mcache中没有可用的内存块,会从mheap中拉取。
  func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {if size <= maxSmallSize {// 小对象分配c := getmcache() // 获取当前P的mcaches := c.alloc(size, needzero)return s}}

2.2 大对象分配(>32KB)

  • 直接从mheap中分配大块内存。
  • 使用span(连续内存块)管理这些大块内存。
  func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {if size > maxSmallSize {// 大对象分配s := mheap_.allocSpan(size)return s}}

3. 垃圾回收(GC)

源码位置: runtime/mgc.go

Go的垃圾回收器使用三色标记清除算法,主要分以下几个阶段:

  1. 标记阶段:
    • 从根对象(全局变量、栈变量、寄存器变量)开始,标记所有可达对象。
  2. 清除阶段:
    • 将未标记的对象回收,释放到mcachemheap
   func gcSweep() {// 遍历所有span,清理未使用的对象for _, s := range mheap_.spans {s.sweep()}}

4. 内存释放

源码位置: runtime/malloc.go

Go会主动将不再使用的大块内存返还给操作系统,调用sysUnusedsysFree实现。

关键点:

  • 小对象:
    • 释放到mcache
    • 如果mcache满了,释放到mheap
  • 大对象:
    • 直接释放到mheap
    • 如果mheap中内存长时间未使用,释放给操作系统。

5. 内存分配中的优化机制

5.1 线程本地缓存(mcache)

  • 减少全局锁竞争。
  • 小对象分配从mcache中直接获取。

5.2 内存对齐

  • Go保证分配的内存地址按对象大小对齐(如8字节、16字节等),以提高访问效率。

5.3 分配池(Free List)

  • 回收的内存会进入Free List,供后续快速分配。

5.4 GC触发条件

  • 当堆的增长超过特定比例(默认100%)时触发GC。

Go的内存分配机制结合了现代内存分配的多种优化技术,能够高效地处理并发场景。关键点在于:

  • 小对象通过mcache优化分配速度。
  • 大对象通过mheap管理,提高内存利用率。
  • 垃圾回收器负责自动清理无用内存,保证程序健壮性。
  • 同时,内存释放机制及时将多余内存返还给操作系统,避免浪费。

6. mcache 和 mheap

深入分析 Go 内存管理中核心模块 mcachemheap 的代码实现,可以更好地理解它们的协同工作方式。以下是详细的源码分析:


1. mcache 模块

1.1 mcache 数据结构

mcache 是每个 P (逻辑处理器) 的本地内存缓存,目的是减少对全局堆的锁争用。
它的源码定义在 runtime/mcache.go

type mcache struct {alloc [numSpanClasses]*mspan // 每个 size class 分配一个 spantiny        uintptr          // 小对象分配缓存tinyoffset  uintptr          // tiny 的当前偏移量local_nlookup uintptr        // 本地分配次数...
}

字段解释:

  • alloc:
    • 存储分配的 spans,按 size class 分类。
    • 每个类的 span 会被重用以分配同类大小的对象。
  • tinytinyoffset:
    • 用于小对象分配(如 mallocgc)。
  • local_nlookup:
    • 用于统计本地内存分配的次数。

1.2 mcache 的主要方法
1.2.1 分配内存 (mcache.alloc)

当分配小对象时,调用 alloc 方法从 mcache 中获取内存:

func (c *mcache) alloc(size uintptr, needzero bool) unsafe.Pointer {sc := sizeToClass(size) // 根据 size 找到对应的 size classs := c.alloc[sc]if s == nil || s.freeindex == s.nelems { // 当前缓存中没有可用的 span,从 mheap 中获取s = mheap_.allocSpan(sc)if s == nil {throw("out of memory")}c.alloc[sc] = s}...return obj
}

工作流程:

  1. 根据 size 计算 size class
  2. 查找对应的 span:
    • 如果 span 有空闲块,从 freeindex 取一个。
    • 如果 span 已满,从 mheap 中分配新的 span。
  3. 返回分配的对象地址。

1.2.2 释放内存 (mcache.releaseAll)

当 GC 发生时,mcache 会将所有未使用的 spans 返还给 mheap

func (c *mcache) releaseAll() {for i := range c.alloc {s := c.alloc[i]if s != nil {mheap_.freeSpan(s) // 释放到 mheapc.alloc[i] = nil}}
}

2. mheap 模块

2.1 mheap 数据结构

mheap 是全局的堆管理器,负责分配和回收大块内存(span),以及为 mcache 提供支持。它的源码定义在 runtime/mheap.go

type mheap struct {spans []*mspan        // 全局管理的 spansfreelist [numSpanClasses]*mspan // 每个 size class 的空闲列表arenas [maxArenas]*heapArena // 内存分配的区域lock mutex           // 全局锁...
}

字段解释:

  • spans:
    • 按页索引管理的所有 spans。
  • freelist:
    • 每个 size class 的空闲 span 链表。
  • arenas:
    • 堆内存分配的底层区域,映射到操作系统的物理内存。
  • lock:
    • 对全局堆操作加锁,避免并发问题。

2.2 mheap 的主要方法
2.2.1 分配 span (mheap.allocSpan)

mcache 需要新的 span 时,会调用 mheap.allocSpan

func (h *mheap) allocSpan(sc spanClass) *mspan {lock(&h.lock) // 加锁,防止并发冲突s := h.freelist[sc]if s != nil {h.freelist[sc] = s.next // 从 freelist 获取 spanunlock(&h.lock)return s}...unlock(&h.lock)return h.grow(sc) // freelist 没有时,从 arenas 扩展
}

工作流程:

  1. freelist 中取出一个空闲的 span。
  2. 如果 freelist 为空,调用 grow 方法,从 arenas 分配新的 span。

2.2.2 回收 span (mheap.freeSpan)

mcache 或垃圾回收器释放内存时,调用 mheap.freeSpan

func (h *mheap) freeSpan(s *mspan) {lock(&h.lock) // 加锁sc := s.spanclass()s.reset() // 重置 span 状态s.next = h.freelist[sc]h.freelist[sc] = s // 回收到 freelistunlock(&h.lock)
}

工作流程:

  1. 通过 spanclass 确定 span 类型。
  2. 重置 span 的元数据。
  3. 将 span 加入 freelist 链表。

2.3 mheap 内存增长 (mheap.grow)

freelist 无法满足分配请求时,从底层 arenas 分配新的 span:

func (h *mheap) grow(sc spanClass) *mspan {p := sysAlloc(_PageSize * npage, &memstats.heap_sys) // 从操作系统分配物理内存if p == nil {throw("out of memory")}s := newMSpan() // 创建新的 spans.init(p, npage) ...return s
}

3. mcache 与 mheap 的协作流程

  1. 分配内存:
    • 小对象: 先从 mcache 中分配。
    • 大对象: 直接通过 mheap 分配。
  2. 回收内存:
    • mcache 释放的内存会回收到 mheap,进入 freelist
  3. GC 的作用:
    • 清理未使用的对象。
    • 调用 mcache.releaseAllmheap.freeSpan 释放无用的 span。

4. 小结一下

  • mcache 是每个 P (逻辑处理器) 的本地缓存,优化小对象分配的性能。
  • mheap 是全局堆管理器,负责大对象分配和全局内存回收。
  • 两者通过 span 的共享和回收机制协作,兼顾性能与内存利用率。
  • 垃圾回收器(GC)在这个体系中扮演清理者的角色,保证内存的高效使用。

关注威哥爱编程,成长路上一起努力,点个赞再走呗。

相关文章:

Go语言内存分配源码分析学习笔记

大家好&#xff0c;我是V 哥。GO GO GO&#xff0c;今天来说一说Go语言内存分配问题&#xff0c;Go语言内存分配的源码主要集中在runtime包中&#xff0c;它实现了Go语言的内存管理&#xff0c;包括初始化、分配、回收和释放等。下面来对这些过程详细分析一下&#xff0c;先赞后…...

【jvm】方法区常用参数有哪些

目录 1. -XX:PermSize2. -XX:MaxPermSize3. -XX:MetaspaceSize&#xff08;Java 8及以后&#xff09;4. -XX:MaxMetaspaceSize&#xff08;Java 8及以后&#xff09;5. -Xnoclassgc6. -XX:TraceClassLoading7.-XX:TraceClassUnLoading 1. -XX:PermSize 1.设置JVM初始分配的永久…...

JAVA环境的配置

首先找到JDK环境的官网。 Java Archive Downloads - Java SE 8u211 and laterhttps://www.oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html 我下载的最后一个x64.exe&#xff0c;下载后&#xff0c;直接双击运行&#xff0c;我这里默认安装到…...

LLM文档对话 —— pdf解析关键问题

一、为什么需要进行pdf解析&#xff1f; 最近在探索ChatPDF和ChatDoc等方案的思路&#xff0c;也就是用LLM实现文档助手。在此记录一些难题和解决方案&#xff0c;首先讲解主要思想&#xff0c;其次以问题回答的形式展开。 二、为什么需要对pdf进行解析&#xff1f; 当利用L…...

MySQL单表查询时索引使用情况

本文针对 MySQL 单表查询时索引使用的几种场景情况进行分析。 假设有一个表如下&#xff1a; CREATE TABLE single_table (id INT NOT NULL AUTO_INCREMENT,key1 VARCHAR(100),key2 INT,key3 VARCHAR(100),key_part1 VARCHAR(100),key_part2 VARCHAR(100),key_part3 VARCHAR(1…...

Qt邮箱程序改良版(信号和槽)

上一版代码可以正常使用,但是会报错 上一篇文章 错误信息 "QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread" 指出了一个问题&#xff0c;即在非主线程中尝试启用或禁用套接字通知器&#xff08;QSocketNotifier&#xff09;…...

入门到精通mysql数据(四)

5、运维篇 5.1、日志 5.1.1、错误日志 错误日志是MySQL中最重要的日志之一,它记录了当mysqld启动和停止,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。 该日志是默认开启的,默认存放目录/var/log…...

Java 设计模式 详解

在Java开发中&#xff0c;设计模式是一种常见的、成熟的解决方案&#xff0c;用于应对特定的设计问题和复杂性管理。以下是一些常用的设计模式&#xff0c;它们可以分为三类&#xff1a;创建型模式、结构型模式和行为型模式。 一、创建型模式 创建型模式主要负责对象的创建&a…...

卡尔曼滤波学习资料汇总

卡尔曼滤波学习资料汇总 其实&#xff0c;当初的目的&#xff0c;是为了写 MPU6050 的代码的&#xff0c;然后不知不觉学了那么多&#xff0c;也是因为好奇、感兴趣吧 有些还没看完&#xff0c;之后笔记也会同步更新的 学习原始材料 【卡尔曼滤波器】1_递归算法_Recursive P…...

linux003.在ubuntu中安装cmake的方法

1.cmake安装程序下载 https://cmake.org/files/v3.30/ 2.解压并下载包 解压cmake压缩包 tar -xvzf cmake.tar.gz进入解压目录 cd cmake-<version>编辑~/.bashrc nano ~/.bashrc在文件的末尾添加如下代码 export PATH/home/xwl/software/cmake/bin:$PATH然后运行以…...

EtherNet/IP转Profinet网关连接发那科机器人配置实例解析

本案例主要展示了如何通过Ethernet/IP转Profinet网关实现西门子1200PLC与发那科搬运机器人的连接。所需的设备有西门子1200PLC、开疆智能Ethernet/IP转Profinet网关以及Fanuc机器人。 具体配置步骤&#xff1a;打开西门子博图配置软件&#xff0c;添加PLC。这是配置的第一步&am…...

自动化运维-检测Linux服务器CPU、内存、负载、IO读写、机房带宽和服务器类型等信息脚本

前言&#xff1a;以上脚本为今年8月1号发布的&#xff0c;当时是没有任何问题&#xff0c;但现在脚本里网络速度测试py文件获取不了了&#xff0c;测速这块功能目前无法实现&#xff0c;后面我会抽时间来研究&#xff0c;大家如果有建议也可以分享下。 脚本内容&#xff1a; #…...

ubuntu24.04设置开机自启动Eureka

ubuntu24.04设置开机自启动Eureka 之前我们是在/root/.bashrc的文件中增加了一条命令 nohup java -jar /usr/software/eurekaServer-auth-prd-03.jar > /usr/software/log.log 2>&1 &但上面这条命令只有在登录root的用户时&#xff0c;才会执行&#xff0c;如果…...

从视频帧生成点云数据、使用PointNet++模型提取特征,并将特征保存下来的完整实现。

文件地址 https://github.com/yanx27/Pointnet_Pointnet2_pytorch?spm5176.28103460.0.0.21a95d27ollfze Pointnet_Pointnet2_pytorch\log\classification\pointnet2_ssg_wo_normals文件夹改名为Pointnet_Pointnet2_pytorch\log\classification\pointnet2_cls_ssg "E:…...

工化企业内部能源能耗过大 落实能源管理

一、精准监测与数据分析 实时准确的数据采集 企业能耗管理系统能够对企业内各种能源&#xff08;如电、水、气、热等&#xff09;的使用情况进行实时监测。通过安装在能源供应线路和设备上的智能传感器&#xff0c;可以精确地采集能源消耗的各项数据&#xff0c;包括瞬时流量、…...

LSTM 和 LSTMCell

1. LSTM 和 LSTMCell 的简介 LSTM (Long Short-Term Memory): 一种特殊的 RNN&#xff08;循环神经网络&#xff09;&#xff0c;用于解决普通 RNN 中 梯度消失 或 梯度爆炸 的问题。能够捕获 长期依赖关系&#xff0c;适合处理序列数据&#xff08;如自然语言、时间序列等&…...

python成长技能之正则表达式

文章目录 一、认识正则表达式二、使用正则表达式匹配单一字符三、正则表达式之重复出现数量匹配四、使用正则表达式匹配字符集五、正则表达式之边界匹配六、正则表达式之组七、正则表达式之贪婪与非贪婪 一、认识正则表达式 什么是正则表达式 正则表达式&#xff08;英语&…...

解决docker报Error response from daemon Get httpsregistry-1.docker.iov2错误

解决docker报Error response from daemon: Get "https://registry-1.docker.io/v2/"错误 报错详情 首先先看一下问题报错效果,我想要拉去nacos-serve&#xff1a;1.1.4的镜像&#xff0c;报如下错误&#xff0c;从报错信息可以看到&#xff0c;用于网络的愿意&…...

【论文分享】利用多源大数据衡量街道步行环境的老年友好性:以中国上海为例

本次给大家带来一篇SCI论文的全文翻译&#xff01;该论文考虑了绿化程度、可步行性、安全性、形象性、封闭性和复杂性这六个指标&#xff0c;提出了一种基于多源地理空间大数据的新型定量评价模型&#xff0c;用于从老年人和专家的角度评估街道步行环境的老年友好程度&#xff…...

说说软件工程中的“协程”

在软件工程中&#xff0c;协程&#xff08;coroutine&#xff09;是一种程序运行的方式&#xff0c;可以理解成“协作的线程”或“协作的函数”。以下是对协程的详细解释&#xff1a; 一、协程的基本概念 定义&#xff1a;协程是一组序列化的子过程&#xff0c;用户能像指挥家…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...