作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!


先看导致问题的核心代码:

func ZeroAllocString() string {
    // 为了不分配内存,存储空间总是从 pool 获得
    buf := pool.Get().([]byte)
    // 业务采用了类似 arena 分配的策略,在一大个池子里面放自己的数据
    temp := buf[10: 10: 4]
    temp = append(temp, "abcd"...)
    s := unsafe.String(unsafe.SliceData(temp), len(temp))
    // 退出生命周期后,回收内存块,以便下次重用
    clear(buf)   // 这里相当于 memset(ptr, 0), "abcd" 这个字符串的内容已经丢失
    buf = buf[:0]
    pool.Put(buf)
    // 但是部分对象已经跳出了所依赖内存的生命周期
    return s
}

总结:

  • 一旦用上 unsafe,就要非常非常小心,驾驭不住就会出问题;
  • 内部的指针错从复杂的指来指去的时候,一定要考虑各个依赖对象的生命周期是否对等
  • 特别是实现一个库的时候:使用者只看见了 string,并不知道简单的用个 string 也会出问题。