Ezreal 书架 Ezreal 书架
Home
  • 《Go程序员面试笔试宝典》
  • 《RabbitMQ 实战指南》
  • 《深入理解kafka》
  • MySQL45讲
  • 透视HTTP协议
  • 结构化数据的分布式存储系统
  • Raft 共识算法
Home
  • 《Go程序员面试笔试宝典》
  • 《RabbitMQ 实战指南》
  • 《深入理解kafka》
  • MySQL45讲
  • 透视HTTP协议
  • 结构化数据的分布式存储系统
  • Raft 共识算法
  • 逃逸分析

    • 逃逸分析是什么
    • 逃逸分析有什么作用
    • 逃逸分析是怎么完成的
    • 如何确定是否发生逃逸
    • Go与其他语言的堆和栈是同一个概念吗
  • 延迟语句

  • 数据容器

  • 通道

  • 接口

  • unsafe

  • context

  • Go程序员面试笔试宝典
  • 逃逸分析
ezreal_rao
2023-03-30

逃逸分析是什么

在编写 C/C++ 代码时,为了提高效率,经常会将返回值修改成返回指针,企图避免构造函数的开销。

其实这里隐藏了一个陷阱:在函数内部定义了一个局部变量,函数结束时返回这个局部变量的地址(指针)。因为这些局部变量是在栈上分配的(即静态内存分配),函数一旦执行完毕,变量占据的内存空间会被销毁,任何对这个返回值做的操作(如解引用),都将扰乱程序的运行,甚至导致程序直接崩溃。比如下面的这段代码:

// c++
int* foo() {
  int t = 3;
  return &t;
}
1
2
3
4
5

有些人可能知道上面这个陷阱,做了一些改进:在函数内部使用 new 运算符构造一个变量 (即动态内存分配),然后返回此变量的地址。因为变量是在堆上创建的,所以在函数退出时不会被销毁。改进后的代码如下:

// c++
int* foo() {
  int* t = new int;
  *t = 3;
  return t;
}
1
2
3
4
5
6

但是,这样就行了吗?新建出来的对象该在何时何地删除呢?调用者可能会忘记删除或者直接将返回值传给其他函数,之后就再也不能删除它了,也就发生了所谓的内存泄漏。

C++ 是公认的语法最复杂的语言,据说没有人可以完全掌握它的语法。而这一切在 Go 语言中就大不相同了,像上面示例的 C++ 代码放到 Go 里没有任何问题:

// go
func foo() *int {
  t := new(int)
  *t = 3
  return t
}
1
2
3
4
5
6

“你表面的光鲜,一定是背后有很多人在支撑”,放到 Go 语言里就是指编译器的逃逸分析:它是编译器执行静态代码分析后,对内存管理进行的优化和简化。

在编译原理中,分析指针动态范围的方法被称之为逃逸分析。通俗来讲,当一个对象的指针被多个方法或线程引用时,则称这个指针发生了逃逸。逃逸分析决定一个变量是分配在堆上还是分配在栈上。

#逃逸分析
上次更新: 5/9/2023, 10:58:32 AM
逃逸分析有什么作用

逃逸分析有什么作用→

最近更新
01
为什么我的MySQL会抖一下
07-15
02
HTTP 性能优化面面观
07-12
03
WebSocket:沙盒里的 TCP
07-12
更多文章>
Theme by Vdoing | Copyright © 2022-2024 Ezreal Rao | CC BY-NC-SA 4.0
豫ICP备2023001810号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式