本文基于Go源码版本1.16、64位Linux平台、1Page=8KB、本文的内存特指虚拟内存
今天我们开始进入《Go语言轻松系列》第二章「内存与垃圾回收」第二部分「Go语言内存管理」。
关于「内存与垃圾回收」章节,会从如下三大部分展开:
第一部分「读前知识储备」已经完结,为了更好理解本文大家可以点击历史链接进行查看或复习。
关于讲解「Go语言内存管理」部分我的思路如下:
mspan
,带出page
、mspan
、object
、sizeclass
、spanclass
、heaparena
、chunk
的概念通过这个思路拆解的目录:
mcache
mcentral
mheap
mcache
是被逻辑处理器p
持有,而不是系统线程m
?page
的概念mspan
的概念object
的概念sizeclass
的概念spanclass
的概念heaparena
的概念chunk
的概念Go的内存统一由内存管理器管理的,Go的内存管理器是基于Google自身开源的TCMalloc
内存分配器为理念设计和实现的,关于TCMalloc
内存分配器的详细介绍可以查看之前的文章《18张图解密新时代内存分配器TCMalloc》。
先来简单回顾下TCMalloc
内存分配器的核心设计。
TCMalloc
内存分配器
TCMalloc
诞生的背景?
在多核以及超线程时代的今天,多线程技术已经被广泛运用到了各个编程语言中。当使用多线程技术时,由于多线程共享内存,线程申在请内存(虚拟内存)时,由于并行问题会产生竞争不安全。
为了保证分配内存的过程足够安全,所以需要在内存分配的过程中加锁,加锁过程会带来阻塞影响性能。之后就诞生了TCMalloc
内存分配器并被开源。
TCMalloc
如何解决这个问题?
TCMalloc
全称Thread Cache Memory alloc
线程缓存内存分配器。顾名思义就是给线程添加内存缓存,减少竞争从而提高性能,当线程内存不足时才会加锁去共享的内存中获取内存。
接着我们来看看TCMalloc
的架构。
TCMalloc
的架构?
TCMalloc
三层逻辑架构
ThreadCache
:线程缓存CentralFreeList
(CentralCache):中央缓存PageHeap
:堆内存
TCMalloc
架构上不同的层是如何协作的?
TCMalloc
把申请的内存对象按大小分为了两类:
我们这里以分配小对象为例,当给小对象分配内存时:
ThreadCache
中分配ThreadCache
的内存不足时,从对应SizeClass
的中央缓存CentralFreeList
获取SizeClass
的PageHeap
中分配采用了和TCMalloc
内存分配器一样的三层逻辑架构:
mcache
:线程缓存mcentral
:中央缓存mheap
:堆内存实际中央缓存central
是一个由136个mcentral
类型元素的数组构成。
除此之外需要特别注意的地方:mcache
被逻辑处理器p
持有,而并不是被真正的系统线程m
持有。(这个设计很有意思,后续会有一篇文章来解释这个问题)
我们更新下架构图如下:
「Go内存分配器」把申请的内存对象按大小分为了三类:
为了清晰看出这三层的关系,这里以堆上分配小对象为例:
mcache
中分配内存central
中分配内存mheap
分配一块内存通过以上的分析可以看出Go内存分配器的设计和开源TCMalloc
内存分配器的理念、思路基本一致。对比图如下:
最后我们总结下:
mcache
:线程缓存mcentral
:中央缓存mheap
:堆内存mcache
是被逻辑处理器p
持有,而不是系统线程m