Go第四课 | 青训营笔记

99 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第4天,今天学习了GC的一些策略,对追踪垃圾回收和引用计数两种GC类型有了清晰的认知;另外学习了Go怎么管理内存和一些字节的实践;最后了解编译器和静态分析的知识,重点学习了函数内联和逃逸分析。

第一课

性能优化

  1. 业务层:具体问题,较大性能收益
  2. 语言层:权衡,多场景

简而言之:数据驱动优化,不要猜

自动内存管理

管理动态内存
目的:1.专注业务2.保证正确性安全性
任务:1.分配 2.找存活对象 3.回收死亡对象

概念

线程分类:Mutator是业务线程,Collector是GC线程
GC分类:serial GC和Parrallel GC会pause,CGC让GC线程和业务线程同时执行

追踪垃圾回收

流程

  1. 标记根对象(全局,线程栈,常量,静态变量)
  2. 标记可达对象(跟对象出发,遍历)
  3. 清理不可达对象

三种清理方式

  1. Copying GC存活对象复制到另外的内存空间

image.png

  1. Mark sweep GC死亡对象内存标记改为“可分配”

image.png

  1. Mark compact GC移动并整理:拷贝存活对象到开头

image.png

分代GC

  1. 假说:对象分配后很快就不再使用
  2. 对象年龄:经历过GC的次数
  3. 策略
    年轻代:copyGC,存活对象少
    老年代:MarksweepGC,对象一直倾向于活着

引用计数

存活条件:当且仅当引用计数>0

优点:内存管理被平坦到程序执行过程,不管runtime实现细节,如cpp的smart ptr

缺点:环形数据结构不能回收;必须原子操作才能保证引用计数的原子性;大数据结构回收会引起pause

第二课

Go怎么管理内存

基本思路:提前内存分块,每次选择合适大小分配
做法:

  1. mmap申请一大块内存,划分为大块,大块划分为特定大小的小块
  2. 缓存:mcache用于快速分配,mcache管理一组mspan。mspan耗尽向mcentral要,mspan为空缓存在mcentral

Go内存管理优化

对象分配高频:每秒分配GB级别的内存
问题:1.小对象多 2.分配路径长

Balanced GC方案

一种指针碰撞风格的GC,分配动作简单

  1. 小对象偏多,小对象合并为大对象GBA分配,
  2. 利用copy GC,减少内存延迟释放(大对象GBA里边有一个小对象,占着不能释放)的情况

编译器和静态分析

编译器结构

image.png

静态分析

  1. 数据流分析&&控制流分析:可根据程序性质代码优化
  2. 过程分析&&过程间分析:复杂

Go编译器优化

通用优化,牺牲编译时间换高效的机器码

函数内联

被调函数副本替换到调用位置 优点:消除函数调用开销 缺点:函数体变大,对于cache不友好,不过绝大情况是正向优化

逃逸分析

指针p 在非当前作用域s的其他区域被访问

总结

有收获,但没有太多实践内容,有点不痛快,赶着做大作业吧。