Golang源码分析:第二章 内存分配

1.内存分配的基本策略

<1>. 每次从操作系统申请⼀⼤块内存(⽐如 1MB),以减少系统调⽤。

<2>. 将申请到的⼤块内存按照特定⼤⼩预先切分成⼩块,构成链表。

<3>. 为对象分配内存时,只需从⼤⼩合适的链表提取⼀个⼩块即可。

<4>. 回收对象内存时,将该⼩块内存重新归还到原链表,以便复⽤。

<5>. 如闲置内存过多,则尝试归还部分内存给操作系统,降低整体开销。

2.基本概念

<1>.内存分配器只管理内存块,并不关⼼对象状态。且不会主动回收内存,由垃圾回收器在完成清理

操作后,触发内存分配器回收操作。

<2>.Golang 的内存分配采⽤了 tcmalloc 的成熟架构

<3>.分配器将其管理的内存块分为两种:

• span: 由多个地址连续的页(page)组成的⼤块内存。

• object: 将 span 按特定⼤⼩切分成多个⼩块,每个⼩块可存储⼀个对象。

照其⽤途,span ⾯向内部管理,object ⾯向对象分配。

<4>.Golang的内存分配器由三种组件组成。

• cache: 每个运⾏期⼯作线程都会绑定⼀个 cache,⽤于⽆锁 object 分配。(分配object)

• central: 为所有 cache 提供切分好的后备 span 资源。(把span切分为object)

• heap: 管理闲置 span,需要时向操作系统申请新内存。(申请/偿还span给操作系统)

<5>.一页内存8KB;以8字节为倍数,总共67种不同大小内存;超过32KB被认为是大对象

<6>.为⼯作线程私有且不被共享的 cache 是实现⾼性能⽆锁分配的核⼼,⽽ central 的作⽤是

在多个 cache 间提⾼ object 利⽤率,避免内存浪费。

<7>.假如 cache1 获取⼀个 span 后,仅使⽤了⼀部分 object,那么剩余空间就可能会被浪费。⽽回收操作将该 span 交还给 central 后,cache1已不再持有该 span,那么该span就会重新分配

<8>.将 span 归还给 heap,可被其他需求获取,重新切分,就可以在不同规格 object 需求间平衡。

3.分配流程:

<1>. 计算待分配对象对应规格(size class)。

<2>. 从 cache.alloc 数组找到规格相同的 span。

<3>. 从 span.freelist 链表提取可⽤ object。

<4>. 如 span.freelist 为空,从 central 获取新 span。

<5>. 如 central.nonempty 为空,从 heap.free/freelarge 获取,并切分成 object 链表。

<6>. 如 heap 没有⼤⼩合适的闲置 span,向操作系统申请新内存块。

4.释放流程:

<1>. 将标记为可回收 object 交还给所属 span.freelist。

<2>. 该 span 被放回 central,可供任意 cache 重新获取使⽤。

<3>. 如 span 已收回全部 object,则将其交还给 heap,以便重新切分复⽤。

<4>. 定期扫描 heap ⾥长时间闲置的 span,释放其占⽤内存。

<5>.⼤对象,直接从 heap 分配和回收。

5.内存对象

//span 对象
type mspan struct {
	next     *mspan    //双向链表
	prev     *mspan    //
	start    pageID    // 起始序号 = (address >> _PageShift)
	npages   uintptr   // 页数
	freelist gclinkptr // 待分配的object链表
}

//三组件
//heap组件
type mheap struct {
	 free [_MaxMHeapList]mspan //页数在127以内的闲置span链表数组
	 freelarge mspan           //页数大于127(>=1MB)的大span链表数组             
	 central [_NumSizeClasses]struct// 每个central对应一种sizeclass
	 {
		mcentral mcentral
	 }
}

//mcentral组件
type mcentral struct {
	sizeclass int32//规格
	nonempty  mspan//链表:尚有空闲object的span
	empty     mspan//链表:没有空闲 object,或已被cache取走的span
}

//cache组件
type mcache struct {
	alloc [_NumSizeClasses]*mspan //以sizeclass为索引管理多个用于分配的span
}

 

6.手工理解图

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值