内存管理

元气蛋蛋 · · 576 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Golang 的内存管理本质上就是一个内存池,只不过内部做了很多的优化。比如自动伸缩内存池大小,合理的切割内存块等等

内存池

golang的程序在启动初,会一次性向操作系统申请一大块内存,这块内存空间会放在一个叫 mheap 的 struct 中管理,mheap负责将这一整块内存分割成不同部分使用,并将其中一部分分割成合适大小分配给用户使用。

概念

page 内存页
span 内存块,一个或多个连续的 page 组成一个 span
object 对象,用来存储一个变量数据,一个span会被分割成相同大小的object
假设 object 的大小是 16B,span 大小是 8K,那么就会把 span 中的 page 就会被初始化 8K / 16B = 512 个 object

image.png

mheap.spans:用来存储 page 和 span 信息,比如一个 span 的起始地址是多少,有几个 page,已使用了多大等等。
mheap.bitmap 存储着各个 span 中对象的标记信息,比如对象是否可回收等等。
mheap.arena_start: 将要分配给应用程序使用的空间。

分配相同或同一范围的大小的内存时,会根据大小去寻找一个sizeclass,span有不同种类,使用sizeclass进行区分,相同sizeclass的span会以链表形式连在一起。


image.png

找到合适的span后会从这个span中找到一个object返回给上层。

mcentral

mheap在初始化时会生成一个大span,如果有需求,会将这个大span切出一个小span放入mcentral进行管理,大 span 由 mheap.freelarge 和 mheap.busylarge 等管理
。如果mcentral不够用了会从mheap.freelarge再切一块。如果 mheap.freelarge 空间不够,会再次从 OS 那里申请内存。

mcache

在mcentral中有一个锁,是为了防止并发情况下申请内存的情况,但是加锁,释放锁,等待锁是一件很浪费时间的事情,所以golang为每一个P申请一个mcache,每个P在申请内存的时候会先从mcache中申请,如果申请不到再从mcentral中申请。从 mcache 上分配内存空间是不需要加锁的,因为在同一时间里,一个 P 只有一个线程在其上面运行,不可能出现竞争。没有了锁的限制,大大加速了内存分配。


image.png
优化

zero size:有些对象的大小为0,例如[0]int, struct{},golang会统一返回一个固定的内存地址

package main

import (
    "fmt"
)

func main() {
    var (
        a struct{}
        b [0]int
        c [100]struct{}
        d = make([]struct{}, 1024)
    )
    fmt.Printf("%p\n", &a)
    fmt.Printf("%p\n", &b)
    fmt.Printf("%p\n", &c)
    fmt.Printf("%p\n", &(d[0]))
    fmt.Printf("%p\n", &(d[1]))
    fmt.Printf("%p\n", &(d[1000]))
}
// 运行结果,6 个变量的内存地址是相同的:
0x1180f88
0x1180f88
0x1180f88
0x1180f88
0x1180f88
0x1180f88

tiny object 在object <= 8B时,会使用sizeclass = 1的span,一般数据类型为 int32,byte, bool以及一些小对象,但是这样可能会导致并不能完全利用8B而导致了浪费并出现了大量的内存碎片。golang在这里做了优化,在 <=16B时,golang都会从 sizeclass=2 的 span 中获取一个 16B 的 object 用以分配,并且将多个对象复用这个16B的object

image.png

大对象:sizeclass最大的span的大小为32K,如果超过这个大小,golang会直接绕过 mcache 和 mcentral,直接从 mheap 上获取,即mheap的freelarge。

内存池的优点:
不需要频繁申请内存了,而是从对象池里拿,程序不会频繁进入内核态。
因为一次性申请一个连续的大空间,对象池会被重复利用,不会出现碎片。
程序频繁访问的就是对象池背后的同一块内存空间,局部性良好。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:元气蛋蛋

查看原文:内存管理

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

576 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传