• Go内存逃逸分析


    Go的内存逃逸及逃逸分析

    Go的内存逃逸

    分析内存逃逸之前要搞清楚一件事 我们编写的程序中的函数局部变量默认是存放在栈上的(补充一点堆上存储的数据的指针 是存放在栈上的 因为指针的大小是可以提前预知的 还有就是Go的基本类型也是存放在栈内的), 而其余的变量是存在堆上的, 栈是由操作系统层面控制 进行内存空间的释放 , 堆默认是程序控制的 像c c++ 是需要标明释放内存空间的位置 , 栈的运行速度远大于堆 . 拥有GC的高级语言回收的便是堆中的内容

    • Go编译器查看内存逃逸的结果 go build -gcflags=-m xxx.go
    • 发生内存逃逸的场景
    1. 函数返回局部变量是一个指针变量
    # 
    type User struct {
      	Name string
    }
    
    func name(s string) *User {
    	u := new(User)  # 这个变量的类型是 *User 指针变量
    	u.Name = s
    
    	return u
    }
    
    func main() {
    
    	user := name("kuQi")
    	fmt.Println(user)
    }
    
    
    # command-line-arguments
    ./main.go:9:6: can inline name
    ./main.go:18:14: inlining call to name
    ./main.go:19:13: inlining call to fmt.Println
    ./main.go:9:11: leaking param: s
    ./main.go:10:10: new(User) escapes to heap  // 造成逃逸
    ./main.go:18:14: new(User) escapes to heap  // 造成逃逸
    ./main.go:19:13: []interface {}{...} does not escape
    <autogenerated>:1: leaking param content: .this
    
    
    

    2.interface的动态类型造成的内存逃逸

    // fmt.Println 接受的参数就是interface动态类型 编译器很难确定接收变量的类型 所有会将123这个变量逃逸到堆
    
    func main() {
    
    	fmt.Println(123)
    }
    
    
    # command-line-arguments
    ./main.go:16:6: can inline main
    ./main.go:20:13: inlining call to fmt.Println
    ./main.go:20:14: 123 escapes to heap
    ./main.go:20:13: []interface {}{...} does not escape
    <autogenerated>:1: leaking param content: .this
    
    

    3.闭包函数产生的内存逃逸

    // 因为函数也是一个指针类型 所以将匿名函数作为返回值时  也会产生内存逃逸 原理类似于 第一个 原因
    
    func BiBao() func() string {
    
    	return func() string {
    
    		return "test"
    	}
    
    }
    
    # command-line-arguments
    ./main.go:24:9: func literal escapes to heap:
    ./main.go:24:9:   flow: ~r0 = &{storage for func literal}:
    ./main.go:24:9:     from func literal (spill) at ./main.go:24:9
    ./main.go:24:9:     from return func literal (return) at ./main.go:24:2
    ./main.go:24:9: func literal escapes to heap
    
    

    4.变量大小无法确定 或 栈空间不足 引发内存逃逸

    ulimit -a    // ulimit -a 可以看到我们的栈空间是8192
    -t: cpu time (seconds)              unlimited
    -f: file size (blocks)              unlimited
    -d: data seg size (kbytes)          unlimited
    -s: stack size (kbytes)             8192
    -c: core file size (blocks)         0
    -v: address space (kbytes)          unlimited
    -l: locked-in-memory size (kbytes)  unlimited
    -u: processes                       2784
    -n: file descriptors                2560
    
    // 超大切片超出栈空间 引发的内存逃逸
    package main
    
    func main() {
    	s := make([]int, 10000, 10000)  // 创建一个超大切片
    	for index, _ := range s {
    		s[index] = index
    	}
    }
    
    
  • 相关阅读:
    未来的产品经理,需要什么样的原型设计工具?
    MySQL基本操作之修改表结构
    基础知识回顾:借助 SSL/TLS 和 NGINX 进行 Web 流量加密
    华为eNSP配置专题-浮动路由及BFD的配置
    在OKR的管理过程过程中,如何和员工进行一次高效的一对一面谈?
    信息抽取/实体关系抽取之UIE
    ReactDOM.render在react源码中执行之后发生了什么?
    荧光标记透明质酸;FITC-Hyaluronic Acid;HA-FITC定制合成
    Python 爬虫实战之爬拼多多商品并做数据分析
    Consul学习笔记之-初识Consul
  • 原文地址:https://www.cnblogs.com/zjaiccn/p/15945657.html