相关配置
- 禁止内连
- 单个函数禁止内连在函数定义前一行添加//go:noinline;
- -gcflags="-l"选项全局禁用内联
- -gcflags=“all=-N -l” 代表的是表示主模块和它所有的依赖都禁用【编译器优化】和【内联】
- marked “go:norace” and -race compilation,
- marked “go:nocheckptr” and -d checkptr compilation,
- marked “go:cgo_unsafe_args”,
- marked as “go:uintptrkeepalive”
- If marked as “go:uintptrescapes”
- Yeswritebarrierrec
- a local function has no fn.Body
判断函数是否可以 inline :
* -gflags=“-m” 显示被内连的函数
* -gflags=“-m -m” 显示原因
* -gcflags=“-d pctab=pctoinline” 显示内敛映射表
内连(inlining)
内连是编译期间的优化,将调用函数的地方直接替换为函数本身(空间换时间),从而减少执行时的跳转操作。golang 编译器默认进行该优化。
内连策略
核心思想是函数足够简单,通过如下条件来定义 简单:
src/cmd/compile/internal/inline/inl.go
CanInline() determines whether fn is inlineable
InlineImpossible() 有具体的判断流程
-
函数足够简单,当解析AST时,Go申请了80个节点作为内联的预算。每个节点都会消耗一个预算。函数的开销不能超过这个预算;
-
不能包含闭包,defer,recover,select;
-
不能以 go:noinline 或 go:unitptrescapes 开头;
-
必须有函数体;
// Inlining budget parameters, gathered in one place
const (
// 解析 ast 的时候节点限制
inlineMaxBudget = 80
inlineExtraAppendCost = 0
// default is to inline if there's at most one call. -l=4 overrides this by using 1 instead.
inlineExtraCallCost = 57 // 57 was benchmarked to provided most benefit with no bad surprises; see https://github.com/golang/go/issues/19348#issuecomment-439370742
inlineExtraPanicCost = 1 // do not penalize inlining panics.
inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
inlineBigFunctionNodes = 5000 // Functions with this many nodes are considered "big".
inlineBigFunctionMaxCost = 20 // Max cost of inlinee when inlining into a "big" function.
)