一般程序的内存分配,从高位到低位依次为

全局静态区:用于存储全局变量、静态变量等;这部分内存在程序编译时已经分配好,由操作系统管理,速度快,不易出错。

栈:函数中的基础类型的局部变量;由程序进行系统调用向操作系统申请,由操作系统管理,速度快。每个线程有自己的栈区。

堆:使用malloc或new申请的内存;由程序运行过程中动态分配任意大小的内存,由程序管理,使用free或者delete删除;频繁的分配和释放必然导致内存碎片。

常量区:存放常量字符串,程序结束后由系统释放。

程序代码区:存放程序的二进制代码。

Go的内存分配:

Go是内置运行时runtime的语言;像这种内置运行时的语言会抛弃传统的内存管理方式,改为自己管理;这样可以完成类似预分配,内存池等操作,以避开系统调用产生的性能问题。Go的内存分配可以分为以下几点:

1. 每次从操作系统申请一大块内存,由Go来对这块内存做分配,减少系统调用。

2. 内存分配算法采用 TCMalloc算法,核心思想是把内存分的非常细,进行分级管理,以降低锁的粒度。

3. 回收对象内存时,并没有将其真正释放掉,而是放回预先分配的大内存中,以便复用。只有内存闲置过多的时候,才会尝试归还部分内存给操作系统,降低整体开销。

Go在程序启动的时候,会分配一块连续的内存(虚拟内存),整体如下:

arena就是所谓的堆区,他把内存分割成 8K大小的页,页是heap中的最小管理单位,一些页组合起来形成了mspan。

bitmap区用于保存arena对应地址(指针大小为 8B,bitmap中一个byte大小的内存对应arena区域中的4个指针,因此大小为 512G/(4 * 8B))中是否保存了对象,以及对象是否被gc过,主要用于gc。

spans区域存放了mspan的指针,用于表示arena区的某一页属于哪个mspan。大小为 512G / 8KB(页的大小) * 8B(指针大小)。在创建 mspan的时候,按页填充对应的spans区域,在回收object时,很容易找到他所属的mspan。

Go内存管理结构

1. class和mspan

go对象管理粒度分为67种大小,也叫class和块。一个page根据class大小分为8K/class size。

class相同且地址连续的pages组成一个span。mspan是span的实际结构,mspan之间组成双向链表关联。

2. mcache 

每个工作线程都有各自的mcache,本地缓存可用的mspan资源,这样各个线程在申请内存的时候无需加锁,对于小于32KB大小的对象,直接通过mcache分配;对于大于23KB的大对象,则需要在mheap中分配。

每个goroutine对于同一个class都有scan和noscan两种mspan队列,其中scan分配给含有指针的对象,noscan分配给不含指针的对象,这样做是为了便于进行垃圾回收,在进行垃圾回收的时候,对于不包含指针的对象,无需进一步扫描是否引用其他活跃对象。

3. mcenter

mcenter为所有mcache提供切分好的mspan。有多少种mspan类型的mspan就有多少个mcenter,每个mcenter保存一种特定类型的mspan,提供两个mspan双端队列,包括已分配出去的和未分配出去的。

所有线程共享,需要加锁访问,但是申请一种 类型的mspan不会影响其他的mcenter.

type mcentral struct {
lock mutex
spanclass spanClass
nonempty mSpanList // list of spans with a free object, ie a nonempty free list
empty mSpanList // list of spans with no free objects (or cached in an mcache) // nmalloc is the cumulative count of objects allocated from
// this mcentral, assuming all spans in mcaches are
// fully-allocated. Written atomically, read under STW.
nmalloc uint64
}

4. mheap

代表Go程序的堆空间,Go程序使用一个mheap来管理堆空间。

当mcenter中没有空闲的mspan时,会向mheap申请。而mheap没有剩余内存时,会向操作系统申请新内存。

另外,对于大于32Kb的大对象,需要在mheap中分配,所有线程共享,需要加锁。

参考:

https://zhuanlan.zhihu.com/p/59125443

https://www.cnblogs.com/unqiang/p/12052308.html

https://zhuanlan.zhihu.com/p/128462868

go - 内存分配机制详解的更多相关文章

  1. ARC内存管理机制详解

    ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数. ...

  2. C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区

    栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面的变量通常是局部变量.函数参数等.在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用.和堆一样 ...

  3. 【校招面试 之 C/C++】第14题 C++ 内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区(堆栈的区别)

    栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面的变量通常是局部变量.函数参数等.在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用.和堆一样 ...

  4. (转)C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区

    程序在内存有五个存在区域: A:动态区域中的栈区  B:动态区域中的栈区 C:静态区域中:全局变量 和静态变量    (这个区域又可以进一步细分为:初始化的全局变量和静态变量    以及    未初始 ...

  5. Java的内存回收机制详解X

    http://blog.csdn.net/yqlakers/article/details/70138786 1 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前 ...

  6. TLFS 内存分配算法详解

    文章目录 1. DSA 背景介绍 1.1 mmheap 1.2 mmblk 2. TLFS 原理 2.1 存储结构 2.2 内存池初始化 2.3 free 2.4 malloc 参考资料 1. DSA ...

  7. object-c(oc)内存管理机制详解

    1.内存的创建和释放 让我们以Object-c世界中最最简单的申请内存方式展开,谈谈关于一个对象的生命周期.首先创建一个对象: 1 2 3 //“ClassName”是任何你想写的类名,比如NSStr ...

  8. linux的vm.overcommit_memory的内存分配参数详解

    公司的redis有时background save db不成功,通过log发现下面的告警,很可能由它引起的: [13223] 17 Mar 13:18:02.207 # WARNING overcom ...

  9. Redis 内存淘汰机制详解

    一般来说,缓存的容量是小于数据总量的,所以,当缓存数据越来越多,Redis 不可避免的会被写满,这时候就涉及到 Redis 的内存淘汰机制了.我们需要选定某种策略将"不重要"的数据 ...

随机推荐

  1. 淘宝 NPM 镜像站切换新域名啦

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 源起 淘宝 NPM 镜像站(npm.taobao.org)自 2014 年 正式对外服务,一开始只是想简单地做 NPM 的中国镜像站点,回馈国内前 ...

  2. 14FPGA综设之图像边沿检测的sobel算法

    连续学习FPGA基础课程接近一个月了,迎来第一个有难度的综合设计,图像的边沿检测算法sobel,用verilog代码实现算法功能. 一设计功能 (一设计要求) (二系统框图) 根据上面的系统,Veri ...

  3. Java9的模块化是什么

    Java9新特性中的模块化到底是什么 Java9中的一个重大特性是增加了一种新型的程序设计组件 - 模块. 官方对模块的定义为:一个被命名的,代码和数据的自描述集合.( the module, whi ...

  4. idea导入gitee下载的项目文件

    前一段时间在学习javaWeb时想要把gitee中的下载的项目在本地环境中跑一遍,然后根据效果再自己做出来. 但是当导入到IDEA中,配置完tomcat后一直报404错误.404是学习javaweb阶 ...

  5. MySQL中的约束,添加约束,删除约束,以及其他修饰

    一.NOT NULL(非空约束)添加非空约束 1)建表时直接添加 CREATE TABLE t_user(user_id INT(10) NOT NULL); 2)通过ALTER 语句 ALTER T ...

  6. java常见面试问题总结

    JDK1.7 并发的HashMap为什么会引起死循环? hashmap如何解决hash冲突,为什么hashmap中的链表需要转成红黑树? hashmap什么时候会触发扩容? jdk1.8之前并发操作h ...

  7. POI Excel索引是从0还是1开始??

    this.workbook.getSheetAt(1).getFirstRowNum() // == 0 this.workbook.getSheetAt(1).getLastRowNum() // ...

  8. Spring容器 从XML 文件中读取bean的定义,并实例化bean?

    解释Spring框架中bean的生命周期. Spring根据bean的定义填充所有的属性. 如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanN ...

  9. Kafka 消费者是否可以消费指定分区消息?

    Kafa consumer消费消息时,向broker发出fetch请求去消费特定分区的消息,consumer指定消息在日志中的偏移量(offset),就可以消费从这个位置开始的消息,customer拥 ...

  10. String s = new String("xyz");创建了几个String Object?二者之间有什么区别?

    两个或一个,"xyz"对应一个对象,这个对象放在字符串常量缓冲区,常量"xyz"不管出现多少遍,都是缓冲区中的那一个.New String每写一遍,就创建一个新 ...