这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天
编译器和静态分析
编译器执行流程: Go 语言编译过程概述 | Go 语言设计与实现
静态分析:
属于编译器后端,不执行程序代码,推导程序行为。分为控制流与数据流
过程内分析与过程间分析:
Intra-procedural analysis: 函数内分析:在函数内进行控制流和数据流的分析 Inter-procedural analysis: 函数间分析:除了函数内的分析,还需要考虑跨函数的数据流和控制流,例如参数传递,函数返回值等
Go编译器优化
函数内联:
内联:编译时将被调用函数的函数体的副本替换到调用位置上,同时重写代码以反映参数的绑定
优点:减少开销,将过程间分析转换为过程内分析
缺点:编译过大
大多数情况内联是正向优化
逃逸分析:
定义:分析代码中指针的动态作用域,即指针在何处可以被访问 大致思路
从对象分配处出发,沿着控制流,观察数据流。若发现指针 p 在当前作用域 s:
作为参数传递给其他函数; 传递给全局变量; 传递给其他的 goroutine; 传递给已逃逸的指针指向的对象; 则指针 p 逃逸出 s,反之则没有逃逸出 s.
优化:未逃逸出当前函数的指针指向的对象可以在栈上分配
对象在栈上分配和回收很快:移动 sp 即可完成内存的分配和回收; 减少在堆上分配对象,降低 GC 负担。
对于微小对象和小对象的内存会首先从mcache和mcentral中获取,这部分要看runtime.malloc代码
微小对象分配
Go中小于16字节的作为微小对象,微小对象会被放入sizeClass为2的span中即16字节,这里并不是说每次微小对象分配都分配一个16字节的空间,而是会把一个16字节的空间按照2、4、8的规则进行字节对齐的形式来存储,比如1字节的char会被分配2字节空间,9字节的数据会被分配2+8=10字节空间。
off := c.tinyoffset
// Align tiny pointer for required (conservative) alignment.
if size&7 == 0 {
off = alignUp(off, 8)
} else if sys.PtrSize == 4 && size == 12 {
// Conservatively align 12-byte objects to 8 bytes on 32-bit
// systems so that objects whose first field is a 64-bit
// value is aligned to 8 bytes and does not cause a fault on
// atomic access. See issue 37262.
// TODO(mknyszek): Remove this workaround if/when issue 36606
// is resolved.
off = alignUp(off, 8)
} else if size&3 == 0 {
off = alignUp(off, 4)
} else if size&1 == 0 {
off = alignUp(off, 2)
}