golang 系列:神秘的内存管理

简介: 内存管理在任何的编程语言里都是重头戏,Golang 也不例外。Go 借鉴了 Google 的 TCMalloc,它是高性能的用于 c++ 的内存分配器。其核心思想是**内存池 + 多级对象管理** ,能加快分配速度,降低资源竞争。

一、概述

内存管理在任何的编程语言里都是重头戏,Golang 也不例外。Go 借鉴了 Google 的 TCMalloc,它是高性能的用于 c++ 的内存分配器。其核心思想是内存池 + 多级对象管理 ,能加快分配速度,降低资源竞争。

二、基础结构

在 Go 里用于内存管理的对象结构主要是下面几个:

mheap、mspan、arenas、mcentral、mcache。

其中,mspan 是一个基础结构,分配内存时,基本以它为单位

mcache、mcentral、mheap 起到了内存池的作用,会被预分配内存,当有对应大小的对象需要分配时会先到它们这一层请求。如果这一层内存池不够用时,会按照下面的顺序一层一层的往上申请内存:

mcache -> mcentral-> mheap -> 操作系统

mspan&&arenas

先来看看 mspan 这个基础结构体。首先,当 Go 在程序初始化的时候,会将申请到的虚拟内存划分为以下三个部分:
内存管理

arenas 也就是动态分配的堆区,它将分配到的内存以 8k 为一页进行管理。
在这里插入图片描述
然而 "页" 这个单位还是太细了,因此再抽象出 mspan 这一层来管理,mspan 表示一组连续的页面。

mspan

mspan 记录了这组连续页面的起止地址、页数量、以及类型规格。

关于 mspan 的类型规格有 67 种,每一种都被定义了一个固定大小,当有对象需要分配内存时,就会挑选合适规格的 mspan 分配给对象。

class  1      2      3      4      5      6  ···   63      64      65      66

bytes  8      16     32     48     64     80 ···  24576   27264   28672   32768

例如给大小为 30B 的对象分配内存时,就会选择类型规格 class 为 3,也就是大小为 32B 的 mspan 分配。这种分配方法跟 linux 用于内存分配的伙伴算法差不多,能有效地减少内存碎片。

刚刚提到虚拟内存划分还有个 bitmap 区域,bitmap 主要用来标记 arena 区域中哪些地址保存了对象, GC 扫描信息以及对象指针信息。

总体上来讲,spans 和 bitmap 区域可以看做是 arenas 区域的元数据信息,辅助内存管理。

mheap && mcentral

mheap 在 Go 里是一个全局对象,用来管理大于 32K 对象的内存分配。

mcentral 维护了各个规格的 mspan。当它的下级 mcache 内存不足时,则会到 mcentral 这里来申请 mspan。

由于 mcentral 有各个规格类型的 mspan,因此当有不同规格的分配请求时,并不会产生并发竞争的问题。只有当同类型规格的 mspan 并发请求分配时,才会有加锁操作。

mheap

mcache

mcache 是提供给 P 的本地内存池。(关于 GPM 模型可以看这篇 golang 重要知识:golang 调度),由于每次只会有一个 Goroutine 在 P 上执行。所以分配内存是不需要竞争的。

mcache 上还有微型分配器,当要分配更小元素:即 <= 16B 时,会在一个 8byte 的 mspan 上分配多个的对象,这样就能更好的利用内存空间。

mcache

三、总体流程

内存分配流程

  • 当要分配大于 32K 的对象时,从 mheap 分配。
  • 当要分配的对象小于等于 32K 大于 16B 时,从 P 上的 mcache 分配,如果 mcache 没有内存,则从 mcentral 获取,如果 mcentral 也没有,则向 mheap 申请,如果 mheap 也没有,则从操作系统申请内存。
  • 当要分配的对象小于等于 16B 时,从 mcache 上的微型分配器上分配。
相关文章
|
6月前
|
存储 编译器 Go
Golang底层原理剖析之内存对齐
Golang底层原理剖析之内存对齐
54 0
|
存储 算法 编译器
Golang 语言的内存管理
Golang 语言的内存管理
49 0
|
安全 编译器 Go
Golang 语言的内存模型
Golang 语言的内存模型
59 0
|
3月前
|
NoSQL Java 测试技术
Golang内存分析工具gctrace和pprof实战
文章详细介绍了Golang的两个内存分析工具gctrace和pprof的使用方法,通过实例分析展示了如何通过gctrace跟踪GC的不同阶段耗时与内存量对比,以及如何使用pprof进行内存分析和调优。
83 0
Golang内存分析工具gctrace和pprof实战
|
3月前
|
Prometheus Cloud Native Java
解决golang 的内存碎片问题
解决golang 的内存碎片问题
72 3
|
3月前
|
Kubernetes 网络协议 测试技术
记一次golang内存泄露
记一次golang内存泄露
45 4
|
存储 缓存 Java
golang 内存管理
golang 内存管理
|
缓存 编译器 Go
golang内存模型-1 chan解决Happens Before
golang内存模型-1 chan解决Happens Before
|
6月前
|
存储 缓存 算法
Golang高性能内存缓存库BigCache设计与分析
【2月更文挑战第4天】分析Golang高性能内存缓存库BigCache设计
204 0
|
6月前
|
Java 编译器 Go
Golang底层原理剖析之内存逃逸
Golang底层原理剖析之内存逃逸
50 0