Go 语言逃逸分析:内存管理的关键

文章目录

  • 前言
  • 1 逃逸分析是什么?
  • 2 逃逸分析的基本思想是什么?
  • 3 逃逸分析的分配原则是什么?
  • 4 如何进行逃逸分析?
  • 5 逃逸分析案例
    • 5.1 变量在函数外存在引用
    • 5.2 引用类型的逃逸
    • 5.3 闭包捕获变量
    • 5.4 变量占用内存较大
  • 6 变量会逃逸到堆上的原因有哪些?
  • 7 如何避免逃逸?
  • 8 逃逸分析的作用有哪些?
  • 9 学习交流

前言

在正式学习逃逸分析时,我们需要提前补充变量的声明周期的概念。


  • 栈(stack):在GO语言中,栈是调用栈(call stack) 的简称。在GO程序运行时,每一个Goroutine单独维护一个自己的栈区仅允许自己使用不能被其他Goroutine使用。一个栈通常包含许多栈帧(stack frame),它描述的是函数之间的调用关系。栈的内存是由编译器自动进行分配释放的。栈区主要存储函数参数局部变量调用函数帧,它们随函数的创建而分配随函数的退出而销毁
  • 堆(heap):与栈(stack)不同的是,堆区的内存是由编译器工程师共同负责管理分配,交给Runtime GC释放。在堆上分配内存时,必须找到一块足够大的内存来存放新的变量数据。在堆上释放内存时,垃圾回收器会扫描内存空间中不被使用的对象并释放其内存。在我们开发过程中,其实考虑内存管理,主要是考虑堆内存的管理。

变量的声明周期与变量作用域的关系

  • 全局变量:它的生命周期与程序的生命周期一致
  • 局部变量:它的生命周期是动态的,从变量创建开始,到变量不再使用结束。
  • 形参和函数的返回值:它们都是属于局部变量,在函数被调用时创建,调用结束时被销毁。

1 逃逸分析是什么?

逃逸分析(Escape Analysis)是一种重要的编译时优化技术,决定将变量分配到 堆(heap)上 还是 栈(stack)上
通过逃逸分析,编译器可以判断变量的生命周期作用范围,从而选择最合适的内存分配方式,以提高程序的性能和减少内存开销


2 逃逸分析的基本思想是什么?

[!warning]- 思考: 如何知道GO变量的生命周期是完全可知的?

  • 判断变量是值类型还是引用类型,值类型是确定的完全可知的,引用类型是不可知的,不知道是否该变量被其他函数使用。
  • 检查变量的生命周期是否是完全可知的,如果是,则在栈上分配内存。
  • 如何检查不是完全可知的,也就是我们说的逃逸,必须在堆上分配内存。

3 逃逸分析的分配原则是什么?

[!warning]- 如何确定参数类型是不确定的?

  • 变量的数据类型采用interface{},编译期无法确定其具体的参数类型,所以分配到堆中。
  • 什么样的数据类型是确定的? 比如:声明了一个确定数据类型int的变量`var num int
  • GO的逃逸分析是在编译期间完成的,编译期间无法确定的参数类型是放在堆中的。
  • 变量在函数外存在引用,则必定放在
  • 变量占用内存较大,则优先放在
  • 变量在函数外部没有引用,则优先放在中。

4 如何进行逃逸分析?

逃逸分析我们可以通过命令查看结果,-gcflags选项用于向 Go 编译器传递编译标志。这些标志可以用来启用或禁用特定的编译器功能,包括逃逸分析

  • 查看基本的逃逸分析和内联信息,适用于一般情况
go build -gcflags="-m" main.go

[!warning]+ 命令解释说明

  • -m:表示输出有关内联(inlining)逃逸分析的信息

  • 查看更详细的优化信息和逃逸分析结果,并禁用内联优化,适用于需要深入调试和分析的情况。
go build -gcflags '-m -m -l'  main.go

[!warning]+ 命令解释说明

  • -m -m:表示多次使用 -m 标志,增加详细程度,会输出更多的优化信息,包括逃逸分析和内联优化的详细信息。
  • -l:表示禁用内联优化。

5 逃逸分析案例

5.1 变量在函数外存在引用

package mainimport "fmt"func createPointer() *int {var x intreturn &x  // x 逃逸到堆上
}func main() {p := createPointer()fmt.Println(*p)
}

[!note]+ 代码解析说明

  • 函数 createPointer 返回了局部变量 x 的地址,这意味着 x 在函数返回后仍然需要存在。
  • 因此,编译器将 x 分配到堆上,并在逃逸分析的输出中提示 &x escapes to heap

5.2 引用类型的逃逸

  • 例如:切片、映射、接口等引用类型的变量,如果它们的底层数据逃逸,则这些变量也会逃逸。
func createSlice() []int {s := make([]int, 10) return s // s 逃逸到堆上 
}

5.3 闭包捕获变量

如果闭包捕获了外部变量,该变量会逃逸到堆上。

func createClosure() func() { var x int return func() { x++ // x 逃逸到堆上 }
}

5.4 变量占用内存较大

func createManySlice() []int {  var s []int  for i := 0; i < 1000; i++ {  s = make([]int, 10)  }  return s // s 逃逸到堆上  
}

6 变量会逃逸到堆上的原因有哪些?

  • 函数返回值:如果返回一个局部变量的指针或引用,该变量会逃逸到堆上。
  • 闭包捕获:如果闭包捕获了外部变量,该变量会逃逸到堆上。
  1. 长生命周期:如果变量的生命周期超出了其作用域,如通过指针或引用传递给其他函数或存储在全局变量中。

7 如何避免逃逸?

避免逃逸,也就是说减少不必要的堆分配。

  • 避免返回局部变量的指针或引用
  • 尽量减少闭包捕获的外部变量
  • 使用值传递而不是指针传递

8 逃逸分析的作用有哪些?

  • 提升内存分配效率:栈上分配比在堆上分配效率更高效,栈上的内存可以自动回收,而堆上的内存需要垃圾回收器管理。
  • 减少垃圾回收开销:减少不必要的堆分配,可以降低垃圾回收的频率和开销。
  • 提高程序性能:优化内存分配,提升程序运行效率。

9 学习交流

为了方便大家一起学习一起进步,我创建了一个学习交流的平台
感兴趣的朋友们可以加我微信:LH913582934,备注:CSDN。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/14810.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录训练营打卡第36天:动态规划解决子序列问题

1.300最长递增子序列 1.问题描述 找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。 2.问题转换 从nums[0...i]的最长的递增的子序列 3.解题思路 每一个位置的n…

经济学问题

问题1 1916年&#xff0c;福特汽车公司以440美元的价格生产了50万辆T型福特汽车。该公司当年盈利6000万美元。亨利福特告诉一位报纸记者&#xff0c;他打算把T型车的价格降至360美元&#xff0c;他希望在这个价格上能卖出80万辆汽车。福特说&#xff1a;“每辆车的利润减少&am…

Flutter 中的 CupertinoPicker 小部件:全面指南

Flutter 中的 CupertinoPicker 小部件&#xff1a;全面指南 在Flutter中&#xff0c;CupertinoPicker是一个用于创建iOS风格的选择器的组件&#xff0c;它允许用户通过滚动来选择一个值。CupertinoPicker可以用于选择日期、时间或者任何可枚举的值。本文将详细介绍CupertinoPi…

C++多态详解

目录 一、多态的概念 二、多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写 4.例题理解&#xff08;超级重要&#xff0c;强烈建议做一下&#xff09; 5.C11 override和 final 6.重载、覆盖&#xff08;重写&#xff09;、隐藏&#xff08;重定义&#xff0…

【yijiej】mysql报错 之 报错:Duplicate entry 字段 for key ‘表名.idx_字段’

一、问题操作 Mysql 进行insert 操作&#xff0c;报错&#xff1a;Duplicate entry 字段 for key ‘表名.idx_字段’ 原因解析&#xff1a;idx 是做的索引键&#xff0c;是具有唯一性二、问题原因&#xff08;三种情况&#xff0c;当前我遇到的情况是第一种&#xff09; 1、当 …

零基础代码随想录【Day42】|| 1049. 最后一块石头的重量 II,494. 目标和,474.一和零

目录 DAY42 1049.最后一块石头的重量II 解题思路&代码 494.目标和 解题思路&代码 474.一和零 解题思路&代码 DAY42 1049.最后一块石头的重量II 力扣题目链接(opens new window) 题目难度&#xff1a;中等 有一堆石头&#xff0c;每块石头的重量都是正整…

(Qt) 默认QtWidget应用包含什么?

文章目录 ⭐前言⭐创建&#x1f6e0;️选择一个模板&#x1f6e0;️Location&#x1f6e0;️构建系统&#x1f6e0;️Details&#x1f6e0;️Translation&#x1f6e0;️构建套件(Kit)&#x1f6e0;️汇总 ⭐项目⚒️概要⚒️构建步骤⚒️清除步骤 ⭐Code&#x1f526;untitled…

【EasyX】快速入门——消息处理,音频

1.消息处理 我们先看看什么是消息 1.1.获取消息 想要获取消息,就必须学会getmessage函数 1.1.1.getmessage函数 有两个重载版本,它们的作用是一样的 参数filter可以筛选我们需要的消息类型 我们看看参数filter的取值 当然我们可以使用位运算组合这些值 例如,我们…

华为CE6851-48S6Q-HI升级设备版本及补丁

文章目录 升级前准备工作笔记本和交换机设备配置互联地址启用FTP设备访问FTP设备升级系统版本及补丁 升级前准备工作 使用MobaXterm远程工具连接设备&#xff0c;并作为FTP服务器准备升级所需的版本文件及补丁文件 笔记本和交换机设备配置互联地址 在交换机接口配置IP&#…

Facebook隐私保护:数据安全的前沿挑战

在数字化时代&#xff0c;随着社交媒体的普及和应用&#xff0c;个人数据的隐私保护问题日益受到关注。作为全球最大的社交平台之一&#xff0c;Facebook承载了数十亿用户的社交活动和信息交流&#xff0c;但与此同时&#xff0c;也面临着来自内外部的数据安全挑战。本文将深入…

AWS Elastic Beanstalk 监控可观测最佳实践

一、概述 Amazon Web Services (AWS) 包含一百多种服务&#xff0c;每项服务都针对一个功能领域。服务的多样性可让您灵活地管理 AWS 基础设施&#xff0c;然而&#xff0c;判断应使用哪些服务以及如何进行预配置可能会非常困难。借助 Elastic Beanstalk&#xff0c;可以在 AW…

【LinuxC语言】一切皆文件的理念

文章目录 引言一、什么是“一切皆文件”&#xff1f;1. 文件柜的类比2. 统一的操作方式3. 举个具体例子4. 设备文件5. 进程和网络连接6. 简化管理 二、这一设计的优势1. 统一接口2. 灵活性3. 简化了系统管理4. 增强了系统安全性 结论 引言 Linux 操作系统以其独特的设计理念和…

如何使用JMeter 进行全链路压测

使用 JMeter 进行全链路压测&#xff1a;详细步骤指南 全链路压测旨在测试整个系统的性能&#xff0c;包括所有的组件和服务。通过 Apache JMeter 进行全链路压测&#xff0c;可以模拟真实用户行为&#xff0c;测试系统在高负载下的表现。以下是详细的步骤指南&#xff0c;分为…

AWTK实现汽车仪表Cluster/DashBoard嵌入式GUI开发(七):快启

前言: 汽车仪表是人们了解汽车状况的窗口,而仪表中的大部分信息都是以指示灯形式显示给驾驶者。仪表指示灯图案都较为抽象,对驾驶不熟悉的人在理解仪表指示灯含义方面存在不同程度的困难,尤其对于驾驶新手,如果对指示灯的含义不求甚解,有可能影响驾驶的安全性。即使是对…

Pytest框架实战二

在Pytest框架实战一中详细地介绍了Pytest测试框架在参数化以及Fixture函数在API测试领域的实战案例以及具体的应用。本文章接着上个文章的内容继续阐述Pytest测试框架优秀的特性以及在自动化测试领域的实战。 conftest.py 在上一篇文章中阐述到Fixture函数的特性&#xff0c;第…

shell循环

一、for循环 用法&#xff1a; for 变量 in 取值列表 do 命令序列 done 例1&#xff1a;打印1到10的数字列表 #!/bin/bashfor i in {1..10} do echo $i done 例2&#xff1a;#批量添加用户,用户名存放在users.txt文件中&#xff0c;每行一个,初始密码均设为123456 #!/bin/bas…

KMP算法【C++】

KMP算法测试 KMP 算法详解 根据解释写出对应的C代码进行测试&#xff0c;也可以再整理成一个函数 #include <iostream> #include <vector>class KMP { private:std::string m_pat;//被匹配的字符串std::vector<std::vector<int>> m_dp;//状态二维数组…

怎样解决Redis高并发竞争Key难点?

Redis作为一种高性能的键值存储系统&#xff0c;在现代分布式系统中发挥着重要作用。然而&#xff0c;高并发场景下对同一Key的操作可能引发竞争条件&#xff0c;给系统稳定性和数据一致性带来挑战。本文将探讨如何解决这一问题&#xff0c;为读者提供有效的应对策略。 1. Red…

【002】FlexBison实现原理

0. 前言 Flex和Bison是用于构建处理结构化输入的程序的工具。它们最初是用于构建编译器的工具&#xff0c;但它们已被证明在许多其他领域都很有用。 &#xfeff; 在第一章中&#xff0c;我们将首先看一点(但不是太多)它们背后的理论&#xff0c;然后我们将深入研究一些使用它…

Mysql和Postgresql创建用户和授权命令

Mysql和Postgresql创建用户和授权命令 MySQL/MariaDB/TiDB mysql -uroot -P3306 -p 输入密码&#xff1a;xxx create user user1% identified by xxx; grant all privileges on *.* to user1%; create user user2% identified by xxx; grant all privileges on *.* to user2%;…