死码消除
什么是死码消除
死码消除(dead code elimination,DCE)是一种编译器优化技术,用处是在编译阶段去掉对程序运行结果没有任何影响的代码。
死码消除有很多好处:减小程序体积,程序运行过程中避免执行无用的指令,缩短运行时间。
应用
全局常量 vs 全局变量
在某些情景下使用全局常量替换全局变量,性能可能会有很大的提升。
在使用常量时,在某些情况下编译器可以直接得到计算结果,进而可以死码消除。
死码消除删除了不必要的分支和语句,不仅二编译后的二进制文件体积减小,而且因为可能少了一些判断分支的条件所以效率也会提升。
有以下两个文件:
maxvar.go
1 | // maxvar.go |
maxconst.go
1 | // maxconst.go |
在编译两个文件之后,发现 maxconst 比 maxvar 的二进制大小少了 10%。
在编译时:
- 首先 max 函数被内联在了 main 函数内部。
1 | func main() { |
- 如果 a 和 b 为常量,在编译时就可以直接计算,得到结果。进而分支消除:
1 | func main() { |
- 又 20 == 10 可以直接计算出来永远为假,所以再次分支消除:
1 | func main() {} |
局部变量
在上述例子中,如果将全局变量改为局部变量,编译器依然可以在编译阶段计算得到值,死码消除依然会生效。
但是如果涉及到了并发操作,则死码消除会失效。
包级别的变量和函数内部的局部变量的推断难度是不一样的。
函数内部的局部变量的修改只会发生在该函数中。但是如果是包级别的变量,对该变量的修改可能出现在:
- 包初始化函数 init() 中,init() 函数可能有多个,且可能位于不同的
.go
源文件。- 包内的其他函数。
- 如果是 public 变量(首字母大写),其他包引用时可修改。
推断 package 级别的变量是否被修改难度是非常大的,从上述的例子看,Go 编译器只对局部变量作了优化。