一文搞懂Golang中的内存逃逸

目录
  • 前言
  • 什么是内存逃逸
  • 查看对象是否发生逃逸
  • 内存逃逸分析的意义
  • 怎么避免内存逃逸
  • 小结

前言

我们都知道go语言中内存管理工作都是由Go在底层完成的,这样我们可以不用过多的关注底层的内存问题,有更多的精力去关注业务逻辑, 但掌握内存的管理,理解内存分配机制,可以让你写出更高效的代码,本文主要总结一下 Golang内存逃逸分析,需要的朋友可以参考以下内容,希望对大家有帮助。

什么是内存逃逸

在了解什么是内存逃逸之前,我们先来了解两个概念,栈内存和堆内存。

堆内存(Heap):一般来讲是人为手动进行管理,手动申请、分配、释放。一般硬件内存有多大堆内存就有多大。适合不可预知大小的内存分配,分配速度较慢,而且会形成内存碎片。

栈内存(Stack):是一种拥有特殊规则的线性表数据结构。由编译器进行管理,自动申请、分配、释放。大小一般是固定的。

通过上面我们可以看出堆分配昂贵,栈分配廉价,在go中所有内存优先栈分配,那么,Go 编译器怎么知道某个变量需要分配在栈上,还是堆上呢?

逃逸分析是用于堆和栈分配进行选择,通过在编译时期做gc,编译器追踪变量在代码块的作用域,判断变量在整个运行周期是否在运行时完全可知,通过校验可以在栈上分配;否则逃逸到堆上;逃逸分析由编译器完成,作用于编译阶段。

查看对象是否发生逃逸

Go 语言工具链提供了查看对象是否逃逸的方法,我们在执行 go build 时,配合使用参数 -gcflags 开启编译器支持的额外功能,例如:

go build -gcflags '-m -l' main.go

-m 会打印出逃逸分析的优化策略,实际上最多总共可以用 4 个 -m,但是信息量较大,一般用 1 个就可以了

-l 会禁用函数内联,在这里禁用掉 inline 能更好的观察逃逸情况,减少干扰。

除了使用编译参数之外,我们还可以使用一种更底层的,更硬核,也更准确的方式来判断一个对象是否逃逸,那就是: 通过反编译命令查看

go tool compile -S main.go

示例:

func main()  {
	sum(1, 2)
}
func sum(a, b int) *int {
	res := a + b
	return &res
}

结果如下,第7行变量 res 逃逸到了堆上

内存逃逸分析的意义

通过逃逸分析,可以尽量把那些不需要分配到堆上的变量直接分配到栈上,堆上的变量少了,会减轻分配堆内存的开销,同时也会减少GC的压力,提高程序的运行速度。

怎么避免内存逃逸

尽量减少外部指针引用,必要的时候可以使用值传递;

对于自己定义的数据大小,有一个基本的预判,尽量不要出现栈空间溢出的情况;

Golang中的接口类型的方法调用是动态调度,如果对于性能要求比较高且访问频次比较高的函数调用,应该尽量避免使用接口类型;

尽量不要写闭包函数,可读性差且发生逃逸。

小结

本文主要介绍了 Go 语言逃逸分析,它可以帮助我们合理分配对象的内存空间。

我们知道分配到堆内存空间的对象,会导致 Go 执行垃圾回收,而垃圾回收会占用系统资源,降低应用程序本身可使用的系统资源。

所以,我们在实际项目开发中,可以借助 Go 工具链分析对象是否会发生逃逸,尽量避免一些不必要的对象逃逸。

到此这篇关于一文搞懂Golang中的内存逃逸的文章就介绍到这了,更多相关Go内存逃逸内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Go 内存分配管理

    目录 一.问题引入 二.几个基本概念 1.RSS,VSS解释 三.Go内存管理机制 1.Goruntime内存延迟归还 2.强制归还内存 一.问题引入 现象:在实际工作项目中,golang项目经常内存报警,现象为在流量增大,或传入很大文件的情况下算法worker内存降低到一定限度之后(100Mb左右),过一段时间才能内存才能自动恢复. Go内存管理机制,Go自己本身会管理内存,释放的内存不会立即归还给操作系统,在一定时间之后才会归还给操作系统,过早的释放内存归还给操作系统会降低性能. 内存泄漏,

  • 浅谈Golang内存逃逸

    目录 1.什么是内存逃逸 2.什么是逃逸分析 3.小结 4.逃逸分析案例 1.函数返回局部指针变量 2.interface类型逃逸 1.interface产生逃逸 2.指向栈对象的指针不能在堆中 3.闭包产生逃逸 4. 变量大小不确定及栈空间不足引发逃逸 5.总结 1.什么是内存逃逸 在一段程序中,每一个函数都会有自己的内存区域分配自己的局部变量,返回值,这些内存会由编译器在栈中进行分配,每一个函数会分配一个栈帧,在函数运行结束后销毁,但是有些变量我们想在函数运行结束后仍然使用,就需要把这个变量

  • 定位并修复 Go 中的内存泄露问题

    Go 是一门带 GC 的语言,因此,大家很容易认为它不会有内存泄露问题. 大部分时候确实不会,但如果有些时候使用不注意,也会导致泄露. 本文案例来自谷歌云的代码,探讨如何找到并修复 Go 中的内存泄露.(确切来说是因为资源泄露导致的内存泄露,除了本文介绍的,还有一些其他泄露的情况) 这篇文章回顾了我如何发现内存泄漏.如何修复它,以及我如何修复 Google 示例 Go 代码中的类似问题,以及我们如何改进我们的库以防止将来发生这种情况. Google Cloud Go 客户端库 [1] 通常在后台

  • Golang 内存管理简单技巧详解

    目录 引言 预先分配切片 结构中的顺序字段 使用 map[string]struct{} 而不是 map[string]bool 引言 除非您正在对服务进行原型设计,否则您可能会关心应用程序的内存使用情况.内存占用更小,基础设施成本降低,扩展变得更容易/延迟. 尽管 Go 以不消耗大量内存而闻名,但仍有一些方法可以进一步减少消耗.其中一些需要大量重构,但很多都很容易做到. 预先分配切片 数组是具有连续内存的相同类型的集合.数组类型定义指定长度和元素类型.数组的主要问题是它们的大小是固定的——它们

  • 一文搞懂Golang中的内存逃逸

    目录 前言 什么是内存逃逸 查看对象是否发生逃逸 内存逃逸分析的意义 怎么避免内存逃逸 小结 前言 我们都知道go语言中内存管理工作都是由Go在底层完成的,这样我们可以不用过多的关注底层的内存问题,有更多的精力去关注业务逻辑, 但掌握内存的管理,理解内存分配机制,可以让你写出更高效的代码,本文主要总结一下 Golang内存逃逸分析,需要的朋友可以参考以下内容,希望对大家有帮助. 什么是内存逃逸 在了解什么是内存逃逸之前,我们先来了解两个概念,栈内存和堆内存. 堆内存(Heap):一般来讲是人为手

  • 一文搞懂JavaScript中的内存泄露

    目录 什么是内存泄漏 怎么检测内存泄漏 Performance Memory 内存泄漏的场景 垃圾回收算法 引用计数 循环引用 标记清除 闭包是内存泄漏吗 总结 以前我们说的内存泄漏,通常发生在后端,但是不代表前端就不会有内存泄漏.特别是当前端项目变得越来越复杂后,前端也逐渐称为内存泄漏的高发区.本文就带你认识一下Javascript的内存泄漏. 什么是内存泄漏 什么是内存?内存其实就是程序在运行时,系统为其分配的一块存储空间.每一块内存都有对应的生命周期: 内存分配:在声明变量.函数时,系统分

  • 一文搞懂Golang中iota的用法和原理

    目录 前言 iota的使用 iota在const关键字出现时将被重置为0 按行计数 所有注释行和空行全部忽略 跳值占位 多个iota 一行多个iota 首行插队 中间插队 没有表达式的常量定义复用上一行的表达式 实现原理 iota定义 const 前言 我们知道iota是go语言的常量计数器,只能在常量的const表达式中使用,在const关键字出现的时将被重置为0,const中每新增一行常量声明iota值自增1(iota可以理解为const语句块中的行索引),使用iota可以简化常量的定义,但

  • 一文搞懂Golang文件操作增删改查功能(基础篇)

    前言 目前,Golang 可以认为是服务器开发语言发展的趋势之一,特别是在流媒体服务器开发中,已经占有一席之地.很多音视频技术服务提供商也大多使用 Golang 语言去做自己的后台服务开发,业内貌似已经达成了某种共识.今天我们不聊特别深奥的机制和内容,就来聊一聊 Golang 对于文件的基本操作. 正文 开始之前,讲一个非常有意思的小桥段.最开始接触 Golang 这种语言的时候,我总感觉它和 Google 单词比较像,所以一度怀疑二者有什么联系.后来一查才发现,二者确实有联系,晕- -因为 G

  • 一文搞懂Python中列表List和元组Tuple的使用

    目录 列表 List 列表是有序的 列表可以包含任意对象 通过索引访问列表元素 列表嵌套 列表可变 元组 Tuple 定义和使用元组 元素对比列表的优点 元组分配.打包和解包 List 与 Tuple 的区别 列表 List 列表是任意对象的集合,在 Python 中通过逗号分隔的对象序列括在方括号 ( [] ) 中 people_list = ['曹操', '曹丕', '甄姫', '蔡文姫'] print(people_list) ['曹操', '曹丕', '甄姫', '蔡文姫'] peopl

  • 一文搞懂如何避免JavaScript内存泄漏

    目录 一.什么是内存泄漏 二.常见的内存泄漏 1.意外的全局变量 2. 计时器 3. 闭包 4. 事件监听器 5.缓存 6.分离的DOM元素 三.识别内存泄漏 1.使用性能分析器可视化内存消耗 2. 识别分离的 DOM 节点 大家好,我是CUGGZ.SPA(单页应用程序)的兴起,促使我们更加关注与内存相关的 JavaScript 编码实践.如果应用使用的内存越来越多,就会严重影响性能,甚至导致浏览器的崩溃.下面就来看看JavaScript中常见的内存泄漏以及如何避免内存泄漏. 一.什么是内存泄漏

  • 一文搞懂Spring中的注解与反射

    目录 前言 一.内置(常用)注解 1.1@Overrode 1.2@RequestMapping 1.3@RequestBody 1.4@GetMapping 1.5@PathVariable 1.6@RequestParam 1.7@ComponentScan 1.8@Component 1.9@Service 1.10@Repository 二.元注解 @Target @Retention @Documented @Inherited 三.自定义注解 四.反射机制概述 4.1动态语言与静态语

  • 一文搞懂Java中的注解和反射

    目录 1.注解(Annotation) 1.1 什么是注解(Annotation) 1.2 内置注解 1.3 元注解(meta-annotation) 1.4 自定义注解 2.反射(Reflection) 2.1 反射和反射机制 2.2 Class类的获取方式和常用方法 2.3 反射的使用 1.注解(Annotation) 1.1 什么是注解(Annotation) 注解不是程序本身,可以在程序编译.类加载和运行时被读取,并执行相应的处理.注解的格式为"@注释名(参数值)",可以附加在

  • 一文搞懂Java中对象池的实现

    目录 1. 什么是对象池 2. 为什么需要对象池 3. 对象池的实现 4. 开源的对象池工具 5. JedisPool 对象池实现分析 6. 对象池总结 最近在分析一个应用中的某个接口的耗时情况时,发现一个看起来极其普通的对象创建操作,竟然每次需要消耗 8ms 左右时间,分析后发现这个对象可以通过对象池模式进行优化,优化后此步耗时仅有 0.01ms,这篇文章介绍对象池相关知识. 1. 什么是对象池 池化并不是什么新鲜的技术,它更像一种软件设计模式,主要功能是缓存一组已经初始化的对象,以供随时可以

  • 一文搞懂C++中string容器的构造及使用

    目录 string容器 string基本概念 string构造函数 string赋值操作 string拼接操作 string查找替换 string字符串比较 string字符读取 string插入和删除 string求子串 string容器 string基本概念 本质: string是c++风格的字符串,不同于c语言的 char*,他本质是一个类 string 和 char*的区别: char*是一个指针 string是一个类,类内部封装了char*来管理字符串,是一个char&型的容器 特点:

随机推荐