关于后端:Go-基于逃逸分析来提升程序性能

5次阅读

共计 1543 个字符,预计需要花费 4 分钟才能阅读完成。

前言

为什么须要理解逃逸剖析?

因为咱们想要晋升程序性能,通过逃逸剖析咱们可能晓得变量是调配到堆上还是栈上,如果调配到栈上,内存的调配和开释都是由编译器进行治理,调配和开释的速度十分快,如果调配到堆上,堆不像栈那样能够主动清理,它会引起频繁地进行垃圾回收(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. 逃逸剖析后能够确定哪些变量能够调配在栈上,栈的性能好。

以上,心愿对你可能有所帮忙。

举荐浏览

  • Go – 应用 sync.Pool 来缩小 GC 压力
  • Go – 应用 options 设计模式
  • Go – json.Unmarshal 遇到的小坑
  • Go – 两个在开发中需注意的小点
  • Go – time.RFC3339 工夫格式化
正文完
 0