当前位置: 首页 > news >正文

Golang内存逃逸

文章目录

    • 1、什么是逃逸
    • 2、逃逸问题相关
    • 3、导致内存逃逸的原因是什么
    • 4、常见发生逃逸的情况和分析
    • 5、逃逸如何分析

1、什么是逃逸

逃逸是指在函数内部创建的对象或变量,在函数结束后仍然被其他部分引用或持有(逃离了变量的作用域)

2、逃逸问题相关

  • 对内存管理的理解栈
    • 栈上的内存分配和释放由编译器自动管理,快但是空间有限
    • 堆:堆上的内存分配需要运行时系统的参与,相对慢但空间大,由GC回收
  • 逃逸可能带来的影响:
    • 分配和回收开销增加
    • 指针引用和内存安全
    • 内存泄露风险
  • 识别逃逸场景,规避不必要的内存逃逸
    • 【并不是所有的逃逸都是不被允许的(闭包函数)】

3、导致内存逃逸的原因是什么

  • 栈空间是否足够
    • 大小是否足够:如果有大变量,肯定会逃逸到堆上
  • 变量作用域
    • 变量或者对象没有以指针的方式返回地址,整个生命周期都在函数内部,随着函数销毁而销毁的话,肯定就不会有逃逸
  • 编译时无法确定类型或大小
    • interface的多态实现,不给他赋值,会在堆上分配
    • 定义切片,不确定大小,也有可能导致内存逃逸
  • Golang的两大内存分配基本原则
    • 栈上的对象只存在栈上,但不能把指针存储到对堆中
    • 栈上指针的生命周期不能超过对象的生命周期

4、常见发生逃逸的情况和分析

  • 指针、slice和map作为返回值

    • 当带有指针的返回值被赋给外部变量或者作为参数传递给其他函数时,编译器无法确定该变量何时停止使用,所以这些变量的内存都应该分配到堆中,逃离当前函数的作用域「逃逸到堆中」
    func f (*int ,[]int, map[int]int) {...
    }
    
  • 向Chan中发送数据的指针或者包括指针的值

    • 可能会被其他协程或者方法引用
    func f() {ch :=make(chan *int, 2)ch <- &i<-ch
    }
    
  • 非直接的函数调用

    • 闭包中引用包外的值,因为闭包执行的生命周期可能会超过函数周期,因此需要放入堆中
    func f() func() {i := 1return func() {fmt.Println(i)}
    }
    
  • 在slice或map中存储指针或者包含指针的值

    • 当把一个指针或者包含指针的值放入slice或map中,编译器无法确定该指针所引用的数据是否会在函数返回后仍然被使用,为了保证数据有效性,会把它分配在堆上。
    func f() {i := 1list := make([]*int, 10)list[0] = &i
    }
    
  • interface类型多态的应用,可能会导致逃逸

    • 接口类型可以持有任意实现了该接口的类型,编译器在编译的时候无法确定具体的动态类型。所以编译器会将接口对象分配到堆上
    func f() {var a action = run{}a.fast()var a1 actiona1 = run{}a1.fast()
    }type action interface {fast()
    }type run struct{}func (r run) fast() {}
    

5、逃逸如何分析

go build -gcflags -m .\main.gomove to heap: i[]int{...} escapes to heapfunc literal escapes to heaprun{} escapes to heap
  • 实际情况例子
main\main.go:28:6: can inline reverseBetween
main\main.go:19:16: inlining call to reverseBetween
main\main.go:5:7: &ListNode{...} escapes to heap
main\main.go:7:9: &ListNode{...} escapes to heap
main\main.go:9:10: &ListNode{...} escapes to heap
main\main.go:11:11: &ListNode{...} escapes to heap
main\main.go:19:16: &ListNode{...} does not escape
main\main.go:28:21: leaking param: head
main\main.go:30:15: &ListNode{...} does not escape

在终端中执行命令分析
!避免不必要的逃逸!

http://www.xdnf.cn/news/513685.html

相关文章:

  • 用代码解读_AI_强化学习在机器人路径规划中的应用与优化
  • nginx相关面试题30道
  • OpenCV-去噪效果和评估指标方法
  • MapReduce-WordCount实现按照value降序排序、字符小写、识别不同标点
  • 【ROS2】 核心概念6——通信接口语法(Interfaces)
  • 定时器相关概念
  • C++(243~263)STL常用算法、遍历算法(for_each,Transform)、查找算法、拷贝和替换、常用算术生成,常用集合算法。
  • 2025抓包工具Reqable手机抓包HTTPS亲测简单好用-快速跑通
  • 小米汽车:新能源赛道的破局者与变革者
  • Python 向量化操作如何实现多条件筛选
  • SpringBoot(一)--- Maven基础
  • 大模型评测体系综述
  • java19
  • 1.2.2
  • Java可变参数与Collections工具类详解
  • [Java实战]Spring Boot整合Elasticsearch(二十六)
  • ARM A64 STR指令
  • LWIP的Socket接口
  • 扫描件交叉合并PDF免费软件 拖拽即合并 + 自动对齐页码 档案整合更轻松
  • C++多态与虚函数详解——从入门到精通
  • 【计算机网络】第一章:计算机网络体系结构
  • 数青蛙 --- 模拟
  • Go语言中函数 vs 方法
  • JVM如何处理多线程内存抢占问题
  • 【Java学习笔记】【第一阶段项目实践】房屋出租系统(面向对象版本)
  • 【Linux】第十九章 管理SELinux安全性
  • 数字格式化库 accounting.js的使用说明
  • “Cloud Native English“云原生时代下的微服务架构设计:从理论到实战全解析
  • 【数据结构】2-3-2 单链表的插入删除
  • 结构型模式:代理模式