我的编程空间,编程开发者的网络收藏夹
学习永远不晚

GoLang内存模型详细讲解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

GoLang内存模型详细讲解

栈内存-协程栈-调用栈

为什么go的栈是在堆上?

go 协程栈的位置: go的协程栈位于go的堆内存,go 的gc 也是对堆上内存进行GC, go堆内存位于操作系统虚拟内存上, 记录局部变量,传递参数和返回值 ,go 使用的参数拷贝传递,如果传递的值比较大 注意传递其指针

go 参数传递 使用 值传递, 也就是说传递结构体时候,拷贝结构体的指针,传递结构体指针时候 拷贝的结构体指针 所以对于 只读参数,不进行修改,最好传递结构体指针

协程栈的空间不够大 怎么办?

本地变量太大,栈帧太多

逃逸分析

不是所有的变量都放在协程栈上,栈帧回收后,需要继续使用的变量,或者 太大的变量,分为指针逃逸,空接口逃逸和大变量逃逸,从栈逃逸分配到堆空间上

指针逃逸 (函数返回的指针被其他使用)

func a() *int {
	v :=0
	return &v // 导致 局部变量会分配在堆行 不会分配栈上
}

空接口逃逸(函数的参数是interface{} 函数的实参很可能会逃逸,主要因为interface{} 类型函数往往会使用反射)

fmt.Println(i) // 入参属于interface{} 空接口, 是否有反射查看值是什么类型 逃逸到堆上

大变量逃逸(过大变量导致的空间不足,超过64KB的变量会逃逸)

// 解决协程的栈空间不足

调用栈帧太多(栈扩容)

  • 解决方式 进行栈扩容,Go的栈初始空间为2KB
  • 在函数调用前判断栈空间morestack
  • 早期使用分段栈(go 1.13) 在逻辑上连接,优点没有空间浪费,栈指针会在不连续的空间跳转,后期 连续栈,缺点 伸缩时候开销大,扩容为原来2倍, 使用比例不足1/4, 变为原来的 1/2

go 堆内存

操作系统的虚拟内存:操作系统给应用提供的虚拟的内存的空间,背后也是物理内存或者磁盘

go 使用 heapArena每次申请虚拟内存单元 64MB,所有的heapArena 组成 堆内存

线性分配据或者链表分配出现空间碎片,所有go 语言中使用分级分配,避免内存的碎片化,每个内存进行分级思想, mspan n内存管理单元

按照需求进行分级分配,runtime.sizeclass.go 进行分配, 总共有68 个级别。

其中 136 个span , mcentral 属于链接头,其中 68个需要GC扫描,其他68个不需要GC扫描。 mcentral 的属于中心索引,使用互斥锁保护,在高并发的场景下 锁冲突严重,参考GMP模型,增加线程的本地缓存。

  • Go 模仿TCmalloc ,建立自己的堆内存架构
  • 使用heapArena 向操作系统申请内存,以mspan 为单位,防止碎片化
  • mcentral 是mspan 的中心索引
  • 使用mcache 本地缓存 大大降低 锁竞争问题

堆如何进行分配

  • Tiny 微对象(0,16B)无指针 – 分配到普通mspan(class 1 - class 67) --将多个微级对象合并成16Byte
  • Small 对象[16B, 32K] – 定制作mspan (class 0)
  • Large 大对象(32KB, +)
  • heapArena 不足的化 会自动申请扩容

go 语言对象的垃圾回收

  • 标记-清除
  • 标记-整理 (go 语言使用分级分配 不需要标记整理)
  • 标记-复制 (只有用内存进行复制,但是空间浪费非常大,Java的新生代) 总结: Go 堆内存的独特方式 进行标记清除掉,如何寻找有用?
  • Gc的起点: 1. 被栈上的指针引用 2.被全局变量引用 3.被寄存器中指针引用
  • Root 节点进行广度优先策略进行搜索(可达性分析标记方法)
  • 暂停所有其他协程,进行可达性分析,找到无引用的GC 属于串行GC 属于在OLD version 中

如何减少GC对性能的分析

如何进行并行GC 提升性能?

难点在于如何进行标记阶段,go 语言采用的 三色标记方法

  • 黑色: 表示已经分析扫描,有用
  • 灰色: 有用,还没进行分析扫描 DFS代替队列
  • 白色: 暂时无用

当三色标记结束后只有黑色的对象,下一次开启恢复成 白色

并发标记的问题(删除)-- 在GC时候 进行对象的指针的变动,针对 并发标记问题 使用 Yuasa 删除屏障, 强制将释放的C指针变成灰色,避免 在GC过程中被粗我䣌标记

Yuasa 删除屏障(s释放的指针进行强制为灰色)

1. 删除屏障可以杜绝在GC标记中删除的问题 ,但是也无法解决并发标记的插入问题

针对插入屏障 使用 Dijkstra 插入屏障 并发标记过程中 将C进行强制置灰,当并发标记过程,新指针指向新的对象,新增的依赖对象 防止错误的GC

混合屏障

被删除的堆对象标记成为灰色

被添加的堆对象标记成为灰色

并发垃圾回收关键在于标记安全,兼顾的安全的效率

GC 优化效率

GC触发的时机

系统定时触发

g0 协程内的sysmon 定时检查 ,在2min 内 forcegcperiod 没有过GC,触发,谨慎调整

用户显示触发

调用runtime.gc 并不推荐

申请内存触发

给申请对象的时候伴随着GC

GC优化原则

尽量少在堆上产生垃圾

内存池化(channel 中 环形池)

减少逃逸 (fmt 包, 返回了指针不是拷贝)

使用空结构体 (不占用空结构体,使用channel 传递空结构体)

使用如下的方式 查看内存

$env:GODEBUG="gctrace=1"

到此这篇关于GoLang内存模型详细讲解的文章就介绍到这了,更多相关Go内存模型内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

GoLang内存模型详细讲解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

GoLang内存模型详细讲解

go官方介绍go内存模型的时候说:探究在什么条件下,goroutine在读取一个变量的值的时,能够看到其它goroutine对这个变量进行的写的结果,Go内存模型规定了一些条件,在这些条件下,在一个goroutine中读取变量返回的值能够确保是另一个goroutine中对该变量写入的值
2022-12-15

Golang设计模式之原型模式详细讲解

如果一个类的有非常多的属性,层级还很深。每次构造起来,不管是直接构造还是用建造者模式,都要对太多属性进行复制,那么有没有一种好的方式让我们创建太的时候使用体验更好一点呢?今天的文章里就给大家介绍一种设计模式,来解决这个问题
2023-01-11

VueMVVM模型超详细讲解

MVVM是Model-View-ViewModel的缩写,MVVM是一种设计思想,这篇文章主要介绍了Vue生命周期和MVVM框架,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2022-11-13

【JVM】JVM内存模型(详细)

目录 一.JVM概述1.jvm简介2.jvm作用3.jvm的内存模型 二.类加载器1.类加载器的作用2.加载器的类型3.双亲委派机制的运行过程4.双亲委派机制优缺点5.为什么要破坏双亲委派机制6.破坏双亲委派机制的方式 三.
2023-08-16

Java内存模型详解

JMM全称JavaMemoryModel,中文翻译Java内存模型,一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,本详细介绍了Java内存模型,感兴趣的同学可以参考一下
2023-05-18

NodeJs内置模块超详细讲解

Node.js内置模块也叫核心模块,跟随Node.js一起安装。console模块提供了一个简单的调试控制台,类似于网络浏览器提供的 JavaScript控制台机制
2023-01-10

Java内存模型JMM详解

Java Memory Model简称JMM, 是一系列的Java虚拟机平台对开发者提供的多线程环境下的内存可见性、是否可以重排序等问题的无关具体平台的统一的保证。(可能在术语上与Java运行时内存分布有歧义,后者指堆、方法区、线程栈等内存
2023-05-30

JAVA内存模型(JMM)详解

这篇文章主要介绍了JAVA内存模型(JMM)详解的相关资料,需要的朋友可以参考下
2022-12-08

Golang设计模式之单例模式详细讲解

单例模式很容易记住。就像名称一样,它只能提供对象的单一实例,保证一个类只有一个实例,并提供一个全局访问该实例的方法。本文就来聊聊Go语言中的单例模式,感兴趣的小伙伴可以了解一下
2023-01-11

Java内存区域与内存模型详解

这篇文章主要介绍“Java内存区域与内存模型详解”,在日常操作中,相信很多人在Java内存区域与内存模型详解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java内存区域与内存模型详解”的疑惑有所帮助!接下来
2023-06-02

Golang设计模式之适配器模式详细讲解

这篇文章主要介绍了使用go实现适配器模式,这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作,需要的朋友可以参考下
2023-01-11

Golang设计模式中的桥接模式详细讲解

桥接模式是一种结构型设计模式,通过桥接模式可以将抽象部分和它的实现部分分离,本文主要介绍了GoLang桥接模式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
2023-01-11

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录