高性能Go语言优化 | 青训营笔记

117 阅读4分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记

性能优化的展开GO语言优化

简介

image-20220519211446790

image-20220519213741126

image-20220519213834884

性能优化本质就是提示软件系统处理能力,在优先计算机资源的情况下,发挥出更多的算力空间


资源高效利用:降低成本,提高效率


确保接口的稳定性,在确保接口保持原功能不变的基础上进行相关性能优化
测试驱动:在测试时刻覆盖尽可能多的场景
隔离性:通过选项控制是否开启优化
可观测性:对优化进行可视化,记录在哪些条件下进行了优化,证明优化是有效的

内存管理优化

自动内存管理

image-20220519214751929

image-20220519214841230

image-20220519215207305

image-20220519215532431

image-20220519215757283

动态内存是指,程序在运行时根据需求动态分配的内存:malloc()

自动内存管理,也就是垃圾回收机制,主要是管理动态内存
自动内存管理最重要的两点就是保证内存使用的正确性和安全性:两次释放同一块内存以及在释放内存之后再次使用这块内存

GC三个重要任务:
	为新对象分配空间
	找到存活对象
	回收死亡对象的内存空间

自动内存管理相关概念:
	mutator:用户线程,修改对象关系的线程
	Collector:GC线程,负责找到存活对象并回收死亡对象

GO内存管理机制

image-20220519215901464

image-20220520152741671

image-20220520155833181

image-20220520155912837

image-20220520161221701

image-20220520161821576

Go内存分配机制类似C++STL分配器中的内存分配机制
	1. 首先调用mmap()先申请一大块内存
	2. 然后将这块内存分割成相同大小的快称为mspan
	3. 再将不同mspan按照不同大小进行再分割,每个mspan分割的大小不同,比如第一块按照8b分割,第二块按照16b分割,这样生成不同大小的块再用于对象分配
	4. 对于mspan按照GC来划分,会分为两类:一种是分配不包含指针的对象,GC不需要扫描noscan mspan;另一种是包含指针的对象,GC需要扫描scan mspan

Go内存分配机制里面用到了缓存
	首先在分配内存时,其基本单位是p也就是线程,当g协程分配内存时会对接到p中,去p中的mcache中寻找一个大小合适的内存
	mcache会管理一组mspan,这一组mspan的分割大小不一,便于后续分配
	当mcache中合适大小的mspan不足时,会向mcentral中获取这种类型的mspan,mcentral中会管理很多大小不一的mspan,管理着内存的分配与释放

Go内存管理优化(Balanced GC)
	在业务中小对象的分配比例很高,面对这种场景进行优化的方法主要是将多次小内存的申请合并到大内存中去
	1. 首先在每个协程中都先分配一个1Kb的内存空间
	2. 如果后续有小内存(<128b)需要分配的时候,先从这个1kb的内存空间中去取,如果从这个1kb空间中拿不到内存的时候再向系统申请内存新的一块1Kb内存
	3. 1kb内存的分配方法使用是指针碰撞法,但依赖这种对象分配的算法又会额外生出新的问题
		比如说当1Kb内存中只用到了很少的内存但导致整个内存不会被释放等问题。这种问题的解决方案可以是使用copying GC的原理管理小对象,当GBA的总大小超过一定阈值时,将GAB中存活的对象复制到另外分配的GAB中,从而可以释放原来的大内存
		

编译器优化

编译器和静态分析

image-20220520163216870

image-20220520165507155

image-20220520165711806

静态分析:控制流和数据流的分析


过程内分析:函数内进行控制流和数据流的分析
过程间分析:函数间的控制流和数据流的分析(利用函数内联同时避免过程间分析)

Go编译器优化

image-20220520165822653

image-20220520170038702

image-20220520170054766

image-20220520170243359

image-20220520170249440

image-20220520220557618

编译器优化:利用较长的编译时间换区更高效的机器码

函数内联


逃逸分析
	逃逸分析是指,指针在当前作用域s之外是否可以被访问,如果可以被访问到则代表逃逸出s,如果不能被访问到则代表没有逃逸出s

Beast mode可以将函数内联,将不必要在堆分配内存的地方改为在栈上分配,对象在栈上分配和回收的时候速度很快,减少了heap的分配降低GC负担