参考博客:极客兔兔
func builderConcat(n int,str string) string { var builder strings.Builder for i := 0;i<n;i++{ builder.WriteString(str) } return builder.String() }
当时用+拼接2个字符串时候是开辟一段新的空间。而strings.Builder,bytes.Buffer,包括切片的[]byte的内存是以倍数申请的。当一万个字符串拼接时,strings.Builder方法的内存消耗大概是+的内存消耗的千分之一。
当silce的容量较小时内存是以2的倍数扩大的,当达到2048时采用新的策略,避免内存申请过大,导致浪费。
切片的结构:
struct { ptr *[]T len int cap int }
性能缺陷:在已有切片的基础上进行切片,不会创建新的底层数组,因为原来的底层数据没有发生变化,内存会一直占用,直到没有变量引用该数组。推荐:用copy
代替re-slice //[x:x]
。
当copy时,切片创建一个新的底层切片,当原切片的底层数组没有引用时内存就会被GC。
range可以很方便地去遍历数组、切片、字典和信道。对nil类型,迭代次数为0。对于通道,for循环迭代直到通道被关闭。
仅遍历下标时for和range性能几乎一样,同时遍历下标和值,for的性能大约是range的2000倍。
range 在迭代过程中返回的是迭代值的拷贝,如果每次迭代的元素的内存占用很低,那么 for 和 range 的性能几乎是一样,例如 []int
。但是如果迭代的元素内存占用较高,例如一个包含很多属性的 struct 结构体,那么 for 的性能将显著地高于 range,有时候甚至会有上千倍的性能差异。对于这种场景,建议使用 for,如果使用range,建议只迭代下标,通过下标访问迭代值,这种使用方式和 for 就没有区别了。如果想使用 range 同时迭代下标和值,则需要将切片/数组的元素改为指针,才能不影响性能。
unsafe.Sizeof
可以得到一个数据类型实例所需要占用的字节数。
空结构体不占据内存空间,因此可以广泛作为各种场景下面的占位符。
有时候使用 channel 不需要发送任何的数据,只用来通知子协程(goroutine)执行任务,或只用来控制协程并发度。这种情况下,使用空结构体作为占位符就非常合适了。