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

Go语言中内存管理逃逸的方法是什么

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

北京

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

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

看不清楚,换张图片

免费获取短信验证码

Go语言中内存管理逃逸的方法是什么

本篇内容介绍了“Go语言中内存管理逃逸的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1. 前言

所谓的逃逸分析(Escape analysis)是指由编译器决定内存分配的位置吗不需要程序员指定。

函数中申请一个新的对象

  • 如果分配在栈中, 则函数执行结束后可自动将内存回收

  • 如果分配在堆中, 则函数执行借宿可交给GC(垃圾回收)处理

有了逃逸分析,返回函数局部变量将变得可能,除此之外,逃逸分析还跟闭包息息相关,了解哪些场景下对象会逃逸至关重要。

2. 逃逸策略

每当函数中申请新的对象,编译器会根据该对象是否被函数外部引用来决定是否逃逸:

  • 如果函数外部没有引用,则优先放到栈中;

  • 如果函数外部存在引用,则必定放到堆中;

注意,对于函数外部没有引用的对象,也有可能放到堆中,比如内存过大超过栈的存储能力。

3. 逃逸场景

3.1 指针逃逸

我们知道Go可以返回局部变量指针,这其实是一个典型的变量逃逸案例,示例代码如下:

package main type Student struct {    Name string    Age  int} func StudentRegister(name string, age int) *Student {    s := new(Student) //局部变量s逃逸到堆     s.Name = name    s.Age = age     return s} func main() {    StudentRegister("Jim", 18)}

函数StudentRegister()内部s为局部变量,其值通过函数返回值返回,s本身为一指针,其指向的内存地址不会是栈而是堆,这就是典型的逃逸案例。

通过编译参数-gcflag=-m可以查看编译过程中的逃逸分析:

D:\SourceCode\GoExpert\class="lazy" data-src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/class="lazy" data-src
.\main.go:8: can inline StudentRegister
.\main.go:17: can inline main
.\main.go:18: inlining call to StudentRegister
.\main.go:8: leaking param: name
.\main.go:9: new(Student) escapes to heap
.\main.go:18: main new(Student) does not escape

可见在StudentRegister()函数中,也即代码第9行显示”escapes to heap”,代表该行内存分配发生了逃逸现象。

3.2 栈空间不足逃逸

看下面的代码,是否会产生逃逸呢?

package main func Slice() {    s := make([]int, 1000, 1000)     for index, _ := range s {        s[index] = index    }} func main() {    Slice()}

上面代码Slice()函数中分配了一个1000个长度的切片,是否逃逸取决于栈空间是否足够大。

直接查看编译提示,如下:

D:\SourceCode\GoExpert\class="lazy" data-src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/class="lazy" data-src
.\main.go:4: Slice make([]int, 1000, 1000) does not escape

我们发现此处并没有发生逃逸。那么把切片长度扩大10倍即10000会如何呢?

D:\SourceCode\GoExpert\class="lazy" data-src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/class="lazy" data-src
.\main.go:4: make([]int, 10000, 10000) escapes to heap

我们发现当切片长度扩大到10000时就会逃逸。

实际上当栈空间不足以存放当前对象时或无法判断当前切片长度时会将对象分配到堆中。

3.3 动态类型逃逸

很多函数参数为interface类型,比如fmt.Println(a …interface{}),编译期间很难确定其参数的具体类型,也会产生逃逸。

如下代码所示:

package main import "fmt" func main() {    s := "Escape"    fmt.Println(s)}

上述代码s变量只是一个string类型变量,调用fmt.Println()时会产生逃逸:

D:\SourceCode\GoExpert\class="lazy" data-src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/class="lazy" data-src
.\main.go:7: s escapes to heap
.\main.go:7: main ... argument does not escape

3.4 闭包引用对象逃逸

某著名的开源框架实现了某个返回Fibonacci数列的函数:

func Fibonacci() func() int {    a, b := 0, 1    return func() int {        a, b = b, a+b        return a    }}

该函数返回一个闭包,闭包引用了函数的局部变量a和b,使用时通过该函数获取该闭包,然后每次执行闭包都会依次输出Fibonacci数列。
完整的示例程序如下所示:

package main import "fmt" func Fibonacci() func() int {    a, b := 0, 1    return func() int {        a, b = b, a+b        return a    }} func main() {    f := Fibonacci()     for i := 0; i < 10; i++ {        fmt.Printf("Fibonacci: %d\n", f())    }}

上述代码通过Fibonacci()获取一个闭包,每次执行闭包就会打印一个Fibonacci数值。输出如下所示:

D:\SourceCode\GoExpert\class="lazy" data-src>class="lazy" data-src.exe
Fibonacci: 1
Fibonacci: 1
Fibonacci: 2
Fibonacci: 3
Fibonacci: 5
Fibonacci: 8
Fibonacci: 13
Fibonacci: 21
Fibonacci: 34
Fibonacci: 55

Fibonacci()函数中原本属于局部变量的a和b由于闭包的引用,不得不将二者放到堆上,以致产生逃逸:

D:\SourceCode\GoExpert\class="lazy" data-src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/class="lazy" data-src
.\main.go:7: can inline Fibonacci.func1
.\main.go:7: func literal escapes to heap
.\main.go:7: func literal escapes to heap
.\main.go:8: &a escapes to heap
.\main.go:6: moved to heap: a
.\main.go:8: &b escapes to heap
.\main.go:6: moved to heap: b
.\main.go:17: f() escapes to heap
.\main.go:17: main ... argument does not escape

4.逃逸总结

栈上分配内存比在堆中分配内存有更高的效率

栈上分配的内存不需要GC处理

堆上分配的内存使用完毕会交给GC处理

逃逸分析目的是决定内分配地址是栈还是堆

逃逸分析在编译阶段完成

5. 注意事项

思考一下这个问题:函数传递指针真的比传值效率高吗?

我们知道传递指针可以减少底层值的拷贝,可以提高效率,但是如果拷贝的数据量小,由于指针传递会产生逃逸,可能会使用堆,也可能会增加GC的负担,所以传递指针不一定是高效的。

“Go语言中内存管理逃逸的方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

免责声明:

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

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

Go语言中内存管理逃逸的方法是什么

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

下载Word文档

猜你喜欢

Go语言中内存管理逃逸的方法是什么

本篇内容介绍了“Go语言中内存管理逃逸的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 前言所谓的逃逸分析(Escape an
2023-07-05

Go语言中内存管理逃逸分析详解

所谓的逃逸分析(Escape analysis)是指由编译器决定内存分配的位置吗不需要程序员指定。本文就来和大家简单分析一下Go语言中内存管理逃逸吧
2023-03-15

golang内存逃逸的原因及解决方法是什么

在Go语言中,内存逃逸指的是在函数内部分配的变量在函数执行完后仍然被其他部分引用,导致变量逃逸到堆上分配内存,而不是在栈上分配内存。内存逃逸会增加垃圾回收的负担,降低程序执行效率。常见导致内存逃逸的原因有:在函数内部创建的变量在函数返回后
2023-10-23

Golang内存管理的优化方法及变量逃逸的影响

Golang中变量逃逸原理对内存管理的影响与优化方法引言:在Golang编程中,内存管理是一个非常重要的主题。Golang通过自动垃圾回收器(GC)来管理内存,对于程序员来说,无需手动分配和释放内存。然而,变量逃逸是一个能够影响内存管理性
Golang内存管理的优化方法及变量逃逸的影响
2024-01-18

C语言动态内存管理的方法是什么

本文小编为大家详细介绍“C语言动态内存管理的方法是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言动态内存管理的方法是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1.为什么需要动态内存分配关于这个
2023-06-29

go语言内存管理的方法有哪些

Go语言内存管理的方法有以下几种:1. 垃圾回收(Garbage Collection):Go语言使用自动垃圾回收机制来管理内存。垃圾回收器会自动检测不再使用的内存,并将其释放。Go语言的垃圾回收器使用了标记-清除算法和三色标记法,可以在不
2023-09-27

不同语言中内存管理与Go语言内存管理的差异

go 语言的内存管理与传统语言(如 c++++、java)不同:传统语言:采用手动内存管理,程序员负责分配和释放内存块。go 语言:采用垃圾回收(gc),自动管理内存,程序员无需手动管理。这种差异导致了以下不同点:手动管理 vs. 自动管理
不同语言中内存管理与Go语言内存管理的差异
2024-04-11

C语言/C++内存管理是什么

本篇内容介绍了“C语言/C++内存管理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、内存在计算机中,每个应用程序之间的内存是相互独
2023-06-16

Lua中内存管理的方法是什么

Lua中的内存管理主要依靠自动垃圾回收器来处理。Lua使用一种基于标记-清除算法的垃圾回收器,它会自动追踪和释放不再使用的内存,避免内存泄漏。除了自动垃圾回收器外,Lua还提供了一些手动管理内存的方法,如手动释放内存、限制内存使用等。可以
Lua中内存管理的方法是什么
2024-04-09

C语言与C++中内存管理的方法

这篇文章主要介绍了C语言与C++中内存管理的方法的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言与C++中内存管理的方法文章都会有所收获,下面我们一起来看看吧。内存分布主要段及其分布每个程序运行起来以后,它
2023-06-30

go语言内存申请和释放的方法是什么

在Go语言中,内存的申请和释放是由Go的垃圾回收器自动管理的,开发者不需要手动申请和释放内存。Go语言使用了自动垃圾回收(Garbage Collection)的机制,它会在程序运行时自动检测和回收不再使用的内存。Go语言的垃圾回收器使用了
2023-10-20

Go语言和C语言在内存管理方面的差异

Go语言和C语言是两种常用的编程语言,它们在内存管理方面有着明显的差异。本文将通过具体的代码示例来展示这两种语言在内存管理方面的不同之处。首先,让我们先来看看C语言中的内存管理。在C语言中,程序员通常需要手动分配和释放内存,这可能会导致内
Go语言和C语言在内存管理方面的差异
2024-03-10

C语言可变参数使用与内存管理的方法是什么

这篇“C语言可变参数使用与内存管理的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言可变参数使用与内存管理的方
2023-07-04

C语言的动态内存管理是什么意思

这篇文章将为大家详细讲解有关C语言的动态内存管理是什么意思,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、动态内存分配(1)用malloc类的函数分配内存;(2)用这些内存支持应用程序;(3)用free
2023-06-29

如何解决Go语言中的内存管理问题?

如何解决Go语言中的内存管理问题?在Go语言中,内存管理是一个重要的话题。由于Go语言自带的垃圾回收器(Garbage Collector)的存在,开发者不需要手动管理内存分配和释放,但这并不意味着我们可以完全忽视内存管理的问题。不合理的内
2023-10-22

golang内存分配管理的方法是什么

Go语言中的内存分配管理主要有两个方法:垃圾回收:Go语言使用了自动垃圾回收(Garbage Collection)来管理内存的分配和回收。垃圾回收器会自动追踪和回收不再使用的内存,减轻了开发人员的负担,也避免了内存泄漏和野指针等问题。Go
2023-10-26

golang手动管理内存的方法是什么

在Go语言中,手动管理内存的方法包括使用unsafe包、手动分配和释放内存以及手动管理指针。使用unsafe包:unsafe包提供了一些不安全的操作,可以绕过Go语言的类型系统和内存管理。例如,可以使用unsafe.Pointer将一个指针
2023-10-23

编程热搜

  • 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动态编译

目录