GO内存管理

内存管理

  1. 向操作系统申请内存,由(Page Allocator)完成
  2. runtime为程序分配内存,由(Object Allocator)完成
  3. runtime为程序做垃圾回收,由(Garbage Collector)完成
  4. 向操作系统归还内存,由(Scavenger)完成
- 向操作系统申请内存和归还内存调用其syscall即可
- 操作系统会为应用程序做虚拟内存与物理内存的映射,之后返回虚拟内存的空间

栈、堆管理

栈的内存管理与线程相关,函数在调用时会把函数和变量压入栈中,一旦线程执行结束则释放相应的内存空间

堆的内存管理(分配内存、释放内存)如下图:

在这里插入图片描述

TCMalloc

在这里插入图片描述

Go内存管理

在这里插入图片描述
Go运行时对堆内存对象管理做了三级划分,mheap,mcentral,mcache表示不同的层级

  • mcache:

    • 是每个处理器(P)私有的内存缓存,用于存储最近分配的小对象
  • mcentral

    • 是一个全局的内存缓存
    • 由一系列的 mSpan 组成,每个 mSpan 包含特定大小类别的对象
  • mheap

    • 管理全局的堆内存,用于分配大块内存
    • 由大量的 mSpan 组成,这些 mSpan 可以包含不同大小类别的对象
  • 分配流程

1. 大对象(>32KB): 直接从mheap上分配
2. 小对象(<=16B): 使用mcache的tiny分配器分配
3. 一般对象(>16B && <=32KB):
	- 首先计算对象的规格大小,然后使用mcache中相应规格大小的mspan分配
	- 如果mcache没有相应规格大小的mspan,则向mcentral申请
	- 如果mcentral没有相应规格大小的mspan,则向mheap申请
	- 如果mheap中也没有合适大小的mspan,则向OS申请
  • 处理器P

    • 局部性原则
      • 由于P持有大块内存,内存分配在P内部进行,从而保证了内存的连续性
      • 内存的局部性提高了CPU Cache的命中率,减少了内存访问延迟
    • 无锁内存管理
      • 内存分配和释放在P内部进行,不需要加锁,避免了线程间的锁竞争
      • 提高了并发性能,特别是在多线程环境下
  • MCache和MCentral的分工

    • MCache:
      • 每个P拥有一个本地缓存MCache,用于快速分配和释放小块内存
      • MCache中的内存分配操作非常高效,因为它们不需要跨P或跨线程进行
    • MCentral:
      • MCentral是多个P共享的中央缓存,当MCache中的内存不足时,P会从MCentral中获取内存
      • 在保证高效内存分配的同时,避免了内存碎片的产生

内存分配

内存分配有两种方式:栈分配和堆分配

- 栈分配是在函数调用时为局部变量分配内存,当函数返回时,这些内存会自动释放
- 堆分配则是通过 new 或者 make 函数动态分配内存,需要GC释放

编译器会自动选择在栈上还是在堆上,来分配局部变量的存储空间
如果一个局部变量在函数返回后仍然被使用,这个变量会从heap,而不是stack中分配内存

内存逃逸

原本应该在栈上分配的内存被分配到了堆上
  • 场景
- 变量的生命周期超出了其作用域
- 大对象的分配
- 闭包引用
-interface 类型上调用方法
- 在 slice 或 map 中存储指针
  • 检测
go build -gcflags -m main.go 
  • 优化策略
- 严格限制变量的作用域
- 对于小型的数据,使用传值而不是传指针
- 避免使用长度不固定的slice切片

内存泄漏

- 在程序执行过程中,已不再使用的内存空间没有被及时释放或者释放时出现了错误
- 导致这些内存无法被使用,直到程序结束这些内存才被释放
  • 分类
// 分为暂时性内存泄漏和永久性内存泄漏
- 暂时性内存泄漏
	- 获取长字符串中的一段导致长字符串未释放
	- 获取长slice中的一段导致长slice未释放
	- defer 导致的内存泄漏
- 永久性内存泄漏
	- goroutine 泄漏导致内存泄漏
	- 定时器使用不当,time.Ticker未关闭导致内存泄漏
	- 不正确地使用终结器(Finalizers)导致内存泄漏
goroutine泄漏导致内存泄漏
  • 本质
goroutine 阻塞,无法继续向下执行,导致此 goroutine 关联的内存都无法释放,进一步造成内存泄漏
  • 两种方式造成内存泄漏:
1. goroutine本身的栈所占用的空间造成内存泄漏
2. goroutine中的变量所占用的堆内存导致堆内存泄漏
  • 泄漏的场景
- channel 阻塞
- select操作在所有case上都阻塞,造成内存泄漏
- 互斥锁没有释放,互斥锁死锁
- 申请过多的goroutine来不及释放
- 在 goroutine 里调用的一些资源,没有 close
  • 发现和定位
1.go pprof获取goroutine profile文件
2.top、traces、list定位内存泄漏的原因
判断依据:
	在节点正常运行的情况下,隔一段时间获取goroutine的数量
	- 如果后面获取的那次,某些goroutine比前一次多,
	- 如果多获取几次,是持续增长的
	- 就极有可能是goroutine泄漏
不正当使用内存场景
  • 大数组作为参数导致短期内内存激增
  • goroutine阻塞拥挤等待,浪费内存
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值