Go语言内存管理(一)内存分配

###Go语言内存管理(一)内存分配

golang作为一种“高级语言”,也提供了自己的内存管理机制。这样一方面可以简化编码的流程,降低因内存使用导致出现问题的频率(C语言使用者尤其是初学者应该深有体会),对程序猿友好。另一方面也可以减少内存相关系统调用,提升性能。

先了解下内存管理大致策略:

  • 申请一块较大的地址空间(虚拟内存),用于内存分配及管理(golang:spans+bitmap+arena->512M+16G+512G)
  • 当空间不足时,向系统申请一块较大的内存,如100KB或者1MB
  • 申请到的内存块按特定的size,被分割成多种小块内存(golang:_NumSizeClasses = 67),并用链表管理起来
  • 创建对象时,按照对象大小,从空闲链表中查找到最适合的内存块
  • 销毁对象时,将对应的内存块返还空闲链表中以复用
  • 空闲内存达到阈值时,返还操作系统

以下,基于go1.9版本,看下golang内存分配实现的基本思路。

###Go内存管理的实现

go的内存管理实现基于TCMalloc(Thread-Caching Malloc)。

TCMalloc是 Google 开发的多级内存分配器,具有对抗内存碎片化,适合高并发场景的特性。据称,它的内存分配速度是 glibc2.3 中实现的 malloc的数倍。

和TCMalloc相同,go的内存分配也是基于两种粒度的内存单位:span和object。span是连续的page,按page的数量进行归类,比如分为2个page的span,4个page的span等。object是span中按预设大小划分的块,也是按大小分类。同一个span中,只有一种类型(大小)的object。

go内存分配主要有三个管理组件:

  • mcache

    Per-P(Processer,具体参见go中G,M,P的概念)私有cache,用于实现无锁的object分配

  • mcentral

    全局内存,为各个cache提供按大小划分好的span

  • mheap

    全局内存,page管理,内存不足时向系统申请

通过将内存分配流程分为三个层级,既能保证Processer级别(mcache)的无锁分配,又能在mcentral级别实现内存全局共享,避免浪费。

go将内存申请按大小分为三种类型:tiny,small,large。tiny是小于16个byte的申请,small是小于32KB的申请,大于32KB为large,三种类型的处理方式有所不同。

1_TinySize = 16 2_MaxSmallSize = 32768

我们以一个small对象为例,看一下内存申请流程:

  1. 计算对象大小,按预定义的sizeclass表(见下)从私有的mcache中找到对应规格的mspan。比如大小为112 byte的对象,对应8192 byte大小的mspan。然后通过mspan的空闲bitmap查找空闲的块,如果空闲块存在,分配完成。

    以上是mcache内的分配操作,不需要加锁。

  2. 如果mspan没有空闲块,则向mcentral申请对应大小的空闲mspan。比如112 byte的对象,需要向mcentral申请8192 byte大小的空闲mspan。

    由于申请获取全局的mspan,需要在mcentral级别加锁。

  3. 如果mcentral中没有空闲mspan,则向mheap申请,并划分object。

  4. 如果mheap没有足够的空闲page,则向操作系统申请不少于1M的page。

以上就是small对象的内存分配流程。

large对象的申请,跳过了mcache和mcentral,直接从mheap中分配。

对于tiny对象的申请,mcache中有专门的内存区域“tiny”来进行特殊处理。“tiny”将对象按大小与tinyoffset(“tiny”当前分配地址)对齐,然后分配,并记录下新的tinyoffset,用于下次分配。如果空间不足,则另外申请16 byte的内存块。

1// sizeclass 2// class bytes/obj bytes/span objects waste bytes 3// 1 8 8192 1024 0 4// 2 16 8192 512 0 5// 3 32 8192 256 0 6// 4 48 8192 170 32 7// 5 64 8192 128 0 8// 6 80 8192 102 32 9// 7 96 8192 85 32 10// 8 112 8192 73 16 11// 9 128 8192 64 0 12// 10 144 8192 56 128 13// 11 160 8192 51 32 14// 12 176 8192 46 96 15// 13 192 8192 42 128 16// 14 208 8192 39 80 17// 15 224 8192 36 128 18// 16 240 8192 34 32 19// 17 256 8192 32 0 20// 18 288 8192 28 128 21// 19 320 8192 25 192 22// 20 352 8192 23 96 23// 21 384 8192 21 128 24// 22 416 8192 19 288 25// 23 448 8192 18 128 26// 24 480 8192 17 32 27// 25 512 8192 16 0 28// 26 576 8192 14 128 29// 27 640 8192 12 512 30// 28 704 8192 11 448 31// 29 768 8192 10 512 32// 30 896 8192 9 128 33// 31 1024 8192 8 0 34// 32 1152 8192 7 128 35// 33 1280 8192 6 512 36// 34 1408 16384 11 896 37// 35 1536 8192 5 512 38// 36 1792 16384 9 256 39// 37 2048 8192 4 0 40// 38 2304 16384 7 256 41// 39 2688 8192 3 128 42// 40 3072 24576 8 0 43// 41 3200 16384 5 384 44// 42 3456 24576 7 384 45// 43 4096 8192 2 0 46// 44 4864 24576 5 256 47// 45 5376 16384 3 256 48// 46 6144 24576 4 0 49// 47 6528 32768 5 128 50// 48 6784 40960 6 256 51// 49 6912 49152 7 768 52// 50 8192 8192 1 0 53// 51 9472 57344 6 512 54// 52 9728 49152 5 512 55// 53 10240 40960 4 0 56// 54 10880 32768 3 128 57// 55 12288 24576 2 0 58// 56 13568 40960 3 256 59// 57 14336 57344 4 0 60// 58 16384 16384 1 0 61// 59 18432 73728 4 0 62// 60 19072 57344 3 128 63// 61 20480 40960 2 0 64// 62 21760 65536 3 256 65// 63 24576 24576 1 0 66// 64 27264 81920 3 128 67// 65 28672 57344 2 0 68// 66 32768 32768 1 0

参考文献:

TCMalloc

图解 TCMalloc

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

常用内核架构

本文分享自天翼云开发者社区《》,作者:JackW宏内核应用程序调用内存分配的API(应用程序接口)函数。处理器切换到特权模式,开始运行内核代码。内核里的内存管理代码按照特定的算法,分配一块内存。把分配的内存块的首地址,返回给内存分配的API函数。内存分配的

Android 优化二 Java内存分配机制及内存泄漏

Java内存分配机制及内存泄漏目录介绍1.JVM内存管理1.1JVM内存管理图1.2Java采用GC进行内存管理。2.JVM内存分配的几种策略2.1静态的2.2栈式的2.3堆式的2.4堆和栈的区别2.5得出结论

Go语言数据类型

\TOC\Go语言是一种静态类型的编程语言,在Go编程语言中,数据类型用于声明函数和变量。数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。编译器在进行编译的时候,就要知道每个值的类型,这样编译器就知道要为这个值分配多少内存,并且知道这段分配的内存表示什么。!(htt