编译相关的分析命令, 在线反汇编:
# -N 禁止优化
# -l 禁止内联
# -S 打印汇编
# -m 打印编译优化策略(包括逃逸情况和函数是否内联,以及变量分配在堆或栈)
# -m=1 -m后面指定的数字越大越详细
go tool compile -m -l main.go
go tool compile -N -l -S main.go
go tool compile -S main.go
go tool compile -N -l main.go && go tool objdump main.o
go tool compile main.go && go tool objdump main.o
string
在部分内置调用上, []byte可以无损的转化为string, 而无需调用runtime.slicebytetostring
目前已知的调用有:
- map查找(备注, map赋值不可以)
var b []byte
var m map[string]string
s := m[string(b)]
- 字符串拼接
var b []byte
s := "ABC" + string(b)
- 字符串比较
var b []byte
bs := "ABC" == string(b)
map
for k := range m {
delete(m, k)
}
- range map 可以一边遍历一边删除
- 以上代码会被优化为
runtime.mapclear
range
源码: cmd/compile/internal/walk/range.go
range会再编译器通过插入代码的方式实现.
interface{}
interface{}
不是指针, 如果赋值是元素, 则会进行复制. 如下面的例子, 修改a和c都不会影响b
var a = item {
name: "aaa",
}
var b interface{} = a
var c = b.(item)
a.name = "bbb"
c.name = "ccc"
fmt.Println(b.(item).name)
interface{}
包含类型和值, 当interface不是nil的时候, 存在类型不为nil, 值为nil的情况, 尤其在error返回的时候要注意, error一定要返回nil, 而不要返回某个类型的nil. 如下面的例子, 输出为 “a is nil” “b is not nil”
var a *item = nil
if a == nil {
fmt.Println(a, "a is nil")
} else {
fmt.Println(a, "a is not nil")
}
var b interface{} = a
if b == nil {
fmt.Println(b, "b is nil")
} else {
fmt.Println(b, "b is not nil")
}
逃逸分析
func print0(v interface{}) {
// v does not escape
}
func print1(v interface{}) int {
// v does not escape
i := len(v.(string))
return i
}
func print3(v interface{}) reflect.Type {
// leaking param: v
rv := reflect.ValueOf(v)
return rv.Type()
}
func print() {
s1 := ""
s2 := ""
s3 := ""
s4 := ""
print0(s1) // s1 does not escape
print1(s2) // s2 does not escape
print1(s3) // s3 does not escape
fmt.Println(s4) // s4 escapes to heap
}
reflect.ValueOf
会造成leaking param
, 可以参考一些golang的知识点中的反射部分.