Go - 基于逃逸分析来提升程序性能

简介: Go - 基于逃逸分析来提升程序性能

文章目录:

  • 前言
  • 什么是逃逸分析?
  • 如何确定是否逃逸?
  • 可能出现逃逸的场景
  • 01
  • 02
  • 03
  • 小结
  • 推荐阅读


前言

为什么需要了解逃逸分析?

因为我们想要提升程序性能,通过逃逸分析我们能够知道变量是分配到堆上还是栈上,如果分配到栈上,内存的分配和释放都是由编译器进行管理,分配和释放的速度非常快,如果分配到堆上,堆不像栈那样可以自动清理,它会引起频繁地进行垃圾回收(GC),而垃圾回收会占用比较大的系统开销。

什么是逃逸分析?

在编译程序优化理论中,逃逸分析是一种确定指针动态范围的方法,简单来说就是分析在程序的哪些地方可以访问到该指针。

简单的说,它是在对变量放到堆上还是栈上进行分析,该分析在编译阶段完成。如果一个变量超过了函数调用的生命周期,也就是这个变量在函数外部存在引用,编译器会把这个变量分配到堆上,这时我们就说这个变量发生逃逸了。

如何确定是否逃逸?

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

可能出现逃逸的场景

01

package main
type Student struct {
 Name interface{}
}
func main()  {
 stu := new(Student)
 stu.Name = "tom"
}

分析结果:

go run -gcflags '-m -l' 01.go
# command-line-arguments
./01.go:8:12: new(Student) does not escape
./01.go:9:11: "tom" escapes to heap

interface{} 赋值,会发生逃逸,优化方案是将类型设置为固定类型,例如:string

package main
type Student struct {
 Name string
}
func main()  {
 stu := new(Student)
 stu.Name = "tom"
}

分析结果:

go run -gcflags '-m -l' 01.go
# command-line-arguments
./01.go:8:12: new(Student) does not escape

02

package main
type Student struct {
 Name string
}
func GetStudent() *Student {
 stu := new(Student)
 stu.Name = "tom"
 return stu
}
func main() {
 GetStudent()
}

分析结果:

go run -gcflags '-m -l' 02.go
# command-line-arguments
./02.go:8:12: new(Student) escapes to heap

返回指针类型,会发生逃逸,优化方案视情况而定。

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

不要盲目使用变量指针作为参数,虽然减少了复制,但变量逃逸的开销可能更大。

03

package main
func main() {
 nums := make([]int, 10000, 10000)
 for i := range nums {
  nums[i] = i
 }
}

分析结果:

go run -gcflags '-m -l' 03.go
# command-line-arguments
./03.go:4:14: make([]int, 10000, 10000) escapes to heap

栈空间不足,会发生逃逸,优化方案尽量设置容量,如果容量实在过大那就没办法了。

小结

  1. 逃逸分析是编译器在静态编译时完成的。
  2. 逃逸分析后可以确定哪些变量可以分配在栈上,栈的性能好。

以上,希望对你能够有所帮助。

推荐阅读

目录
相关文章
|
14天前
|
安全 Go 开发者
代码之美:Go语言并发编程的优雅实现与案例分析
【10月更文挑战第28天】Go语言自2009年发布以来,凭借简洁的语法、高效的性能和原生的并发支持,赢得了众多开发者的青睐。本文通过两个案例,分别展示了如何使用goroutine和channel实现并发下载网页和构建并发Web服务器,深入探讨了Go语言并发编程的优雅实现。
28 2
|
27天前
|
Dart JavaScript Java
Dart、Go、性能比较
Dart和Go都是高性能的编程语言,但它们在性能方面的表现有所不同。
49 4
|
29天前
|
算法 Java 编译器
你为什么不应该过度关注go语言的逃逸分析
【10月更文挑战第21天】逃逸分析是 Go 语言编译器的一项功能,用于确定变量的内存分配位置。变量在栈上分配时,函数返回后内存自动回收;在堆上分配时,则需垃圾回收管理。编译器会根据变量的使用情况自动进行逃逸分析。然而,过度关注逃逸分析可能导致开发效率降低、代码复杂度增加,并且对性能的影响相对较小。编译器优化通常比人工干预更准确,因此开发者应更多关注业务逻辑和整体性能优化。
|
2月前
|
Kubernetes Go 持续交付
一个基于Go程序的持续集成/持续部署(CI/CD)
本教程通过一个简单的Go程序示例,展示了如何使用GitHub Actions实现从代码提交到Kubernetes部署的CI/CD流程。首先创建并版本控制Go项目,接着编写Dockerfile构建镜像,再配置CI/CD流程自动化构建、推送Docker镜像及部署应用。此流程基于GitHub仓库,适用于快速迭代开发。
49 3
|
2月前
|
Kubernetes 持续交付 Go
创建一个基于Go程序的持续集成/持续部署(CI/CD)流水线
创建一个基于Go程序的持续集成/持续部署(CI/CD)流水线
|
1月前
|
算法 安全 Go
Python与Go语言中的哈希算法实现及对比分析
Python与Go语言中的哈希算法实现及对比分析
40 0
|
1月前
|
机器学习/深度学习 自然语言处理 Go
Python与Go在AIGC领域的应用:比较与分析
Python与Go在AIGC领域的应用:比较与分析
40 0
|
2月前
|
IDE Go 数据处理
Go to Learn Go之第一个Go程序
Go to Learn Go之第一个Go程序
25 0
|
2月前
|
缓存 安全 Java
如何利用Go语言提升微服务架构的性能
在当今的软件开发中,微服务架构逐渐成为主流选择,它通过将应用程序拆分为多个小服务来提升灵活性和可维护性。然而,如何确保这些微服务高效且稳定地运行是一个关键问题。Go语言,以其高效的并发处理能力和简洁的语法,成为解决这一问题的理想工具。本文将探讨如何通过Go语言优化微服务架构的性能,包括高效的并发编程、内存管理技巧以及如何利用Go生态系统中的工具来提升服务的响应速度和资源利用率。
|
3月前
|
存储 缓存 安全