性能优化与自动内存管理 | 青训营笔记

106 阅读3分钟

Go 语言原理与实践课程-9 & 10

概述:内存优化和编译器优化

背景知识

性能优化的原因

优化的层次:业务层优化,语言运行时优化(本次重点)

优化的可维护性(测试、文档)

自动内存管理背景-go内存管理

概述:概念-标记垃圾回收&分代垃圾回收&引用计数

---->概念

mutator:业务线程,分配对象、修改对象指向关系(用户启动的、goroutine都算)

collector:GC线程

paralle:多个collector(相对于serial)

concurrent:collector和mutator同时

那么collector必须感知对象间指向关系的改变

---->评价标准

正确性:不能删除活的

吞吐率:1-GC和程序总时间比值

暂停时间、内存开销

推荐书籍-the garbage collection handbook

---->追踪的垃圾回收

步骤:标记根对象(栈、全局变量等等)-》标记可达对象-》清理不可达对象

清理的方法:copying GC、mark-sweep GC(只标记)、mark-compact GC(原地整理对象)

根据对象生命周期选择

---->分代垃圾回收

基于分代假说 ;年龄基于经过GC的次数;把不同对象放不同区域;不同区域不同策略:年轻代copying老年代mark-sweep

---->引用计数

优点:不打断程序+不需要了解运行时(如c++智能指针)

缺点:开销大并行需要原子+环形引用(weak_ptr)+内存开销+回收时需要暂停

GO内存分配与内存分配优化 class 10

概述:GO内存分配与内存分配优化

---->分块

向系统要大块如4M mspan 8K

每个mspan内部再划分块,不同mspan划分大小不同,还分为no-scan和scan mspan,看有没有指针GC要不要扫不扫描

---->缓存

mcache-mcentral

---->必要性

每秒很多次

小内存很多

路径很长 G M P mcache mspan memory block

---->字节怎么做

Balance GC

每个G绑定1kb的GAB(goroutine allocation buffer)区,分配给noscan&&<128b的对象

Base Top end指针碰撞分配

每个g都有所以不用原子

  • 缺点:延迟释放
  • 解决:GAB比较慢了就copy gc

编译器优化背景-go编译器优化

概述:编译器基本概念和静态分析(控制流和数据流、过程内和过程间分析)

---->编译器与编译过程

词法分析-----(词素lexeme)----语法分析----(抽象语法树AST)-----语义分析-----decorated AST----中间表示----IR(机器无关)-----(从这往后叫后端,具体主要讲后端)代码优化-----IR(机器无关)----代码生成---------目标代码

---->静态分析

不执行代码分析代码性质

控制流,数据流

过程内、过程间(包括函数返回等等)

---->编译器优化

为什么做:用户无感知&通用

怎么做:牺牲编译时间提高重复执行的代码的性能

方法:函数内联、逃逸分析、默认栈大小调整、边界检查消除、循环展开

---->函数内联

减少函数调用&过程间变成过程内供其他模块分析

例子是通过编译器参数让它不inline

分享:快速用benchmark去检查性能

缺点:函数体变大,cpu可能没法放一个patch,复制时太大等等。可以根据一些性质(如长短)决定是否内联

Beast mode(字节产品):解决了go 的保守内联策略,interface、defer

---->逃逸分析

概念:分析指针动态作用域,参数传递、传递给全局、传递给其他g,传递给已逃逸的对象

Beast mode:因为减少了内联所以也减少了逃逸(可以在栈上分配,减轻gc负担)