20200311

@zhangyuwei

Plan

go源码学习

Notes

内存分配

基本策略:

1.每次从操作系统申请一大块内存,以减少系统调用。

2.将申请到的大块内存按照特定大小预先切成小块,构成链表。

3.为对象分配内存时,只须从大小合适的链表提取一个小块即可。

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

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

注:内存分配器只管理内存块,不关心对象状态,不会主动回收内存,垃圾回收起在完成清理操作后,会触发内存分配器的回收操作。

分配器将管理的内存块分为两种:

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

2.object:将span按特定大小切分成多个小块,每个小块可存储一个对象。

分配器按页数来区分不同大小的span(个人理解,页的大小是固定的,页数越大,span越大)

用于存储对象的object,按8字节倍数分为n种。比如大小24的object可存储范围是17~24字节的对象。这样虽然会造成内存浪费,好处在于分配器只须面对有限集中规格的小块内存,优化了分配和复用管理策略。

分配器由三种组件组成:

1.cache:每个运行期工作线程都会绑定一个cache,用于无锁object分配。

2.central:为所有cache提供切分好的后背span资源。

3.heap:管理闲置span,需要时向操作系统申请新内存。

分配流程:

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

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

3.从span.freelist链表提取可用object。

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

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

6.如果heap没有大小合适的闲置span,向操作系统申请新内存块。

释放流程:

1.将标记为可回收的object交换给所属span.freelist。

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

3.如果span已收回全部object,则将其交还给heap,以便重新切分复用、

4.定期扫描heap里长时间闲置的span,释放其占用的内存。

注:以上不包括大对象,它直接从heap分配和回收。

More

1.cache是工作线程私有且不被共享的,它是高性能无锁分配的核心。

2.central的作用是在多个cache间提高object的利用率,避免内存浪费。

3.将span归还给heap,是为了在不同规格object需求间平衡。