-
slice
-
内存预分配
- 尽可能在使用make()初始化切片时提供容量信息
- 因为slice本质是一个包含了数组、当前长度和容量的数据结构,在新增元素超出容量后,会导致内存重分配和原有元素的移动,频繁的扩容操作会导致性能的损耗,所以如果提前预知切片容量并指定的话,会减少不必要的扩容
-
大内存未释放
- 在已有的很大的切片上创建很小的切片,可能会导致原始切片无法释放
- 因为在已有的切片基础上创建切片不会创建新的底层数组,所以在原始大切片上新建小切片的时候,原始切片在内存上有引用,无法释放
- 可以使用copy代替re-slice
-
-
map
-
内存预分配
- 原理与slice预分配类似
-
-
字符串处理
- 使用strings.Buffer而不是+
- 因为字符串时不可变类型,使用+时每次都会重新分配内存,而strings.Buffer底层时[]byte数组,内存扩容策略,不需要每次拼接重新分配内存
-
空结构体struct{}占位
- 空结构体实例本身不占据任何的内存空间,可作为各种场景下的占位符使用
- 例如可以使用map来实现set,因为对于这个场景下,只需要使用map的键,即使将map的值设置为bool类型,每个键值对也会多占据一个字节空间
-
使用atomic包
-
在涉及竞态的时候,对一个共享变量,使用atomic比加锁解锁要快
-
例如
-
type atomicCounter struct { i int32 } func AtomicAddOne(c *atomicCounter) { atomic.AddInt(&c.i, 1) } /*-----------------------------------------*/ type mutexCounter struct { i int32 m sync.Mutex } func MutexAddOne(c *mutexCounter) { c.m.Lock() c.i++ c.m.Unlock() }在上述代码中,上面的的方式就要比下面的快
-
这是因为锁的实现是通过操作系统来实现,属于系统调用,atomic操作时通过硬件实现,效率比锁高,sync.Mutex应该用来保护一段逻辑,而不仅仅是一个变量
-