Golang内存管理——堆分配

go语言的内存自动分配和回收的,因此内存的使用流程大致为:获取内存——分配内存——回收内存——再分配内存。

其中分配内存分为两方面,堆内存分配和栈内存分配,堆内存和栈内存是两种不同的分配方式,本篇文章主要是堆内存的分配方式。

1. 自主内存管理

Go语言为了方便内存的自主管理,一开始启动的时候会向操作系统申请一大块连续的内存,后续的内存分配都是基于这一大块内存的。如果程序运行过程中,内存不足了,Go语言会再向操作系统进行内存的申请。

为了高效的进行内存管理,Go语言将申请到的内存划分为三个区域,分别为spans、bitmap、arena。其中arena是堆区,GO语言将其划分为一个个8KB的page页,程序运行过程中的内存都是从arena堆区进行分配的。spans和bitmap是为了对arena堆区的高效管理而设置的。

Go语言的三个内存区域

2. mspan 和 ClassID表

我们程序的运行,从使用的角度看,以对象为基本单位的。比如:函数是一个对象、goroutine是一个对象、slice是一个对象。因此,为了实现从对象到内存页之间的映射,Go语言引入了一个mspan结构体。mspan是内存管理的基本单位,每一个span包含一个或多个连续的页。为了满足小对象的分配,会将span中的一页划分为更小的粒度,而对于大对象比如超过页的大小,则会通过多页实现。每个span用于管理特定的class对象,根据对象的大小,span将一个或多个页拆分成多个块进行管理。

mspan的结构体定义如下:位置 runtime:mheap.go 一些字段已经省略了

type mspan struct {
	next *mspan     // 链表后向指针,用于将span链接起来
	prev *mspan     // 链表前向指针,用于将span链接起来
	startAddr uintptr // 起始地址,即所管理页的地址
	npages    uintptr // 该span中占用的page页数

    //作用于GC,垃圾会有的时候会使用这三个字段
	allocBits  *gcBits //分配位图,每一位代表一个块是否已分配
	gcmarkBits *gcBits
	pinnerBits *gcBits 

	allocCount  uint16        // 该Span中已经分配的对象数量
	spanclass   spanClass     // 该Span的等级,一个特定的span中存储特定的ClassID大小的对象
	elemsize    uintptr       // 块大小,该span中存储特定ClassID的大小
}

 Class等级列表如下:
源码位置:runtime:sizeclasses.go

划分如此多的Class等级的目的:

  1. 尽可能地减少内存浪费
  2. 降低从全局缓存中获取特定SpanClass锁的粒度
// class  bytes/obj  bytes/span  objects  tail waste  max waste  min align
//     1          8        8192     1024           0     87
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值