性能优化分析 | 青训营笔记

43 阅读2分钟

这是我参与「第五届青训营 」笔记创作活动的第3天

性能优化案例

  1. 预分配内存——slice()
  • 尽可能在使用make()初始化切片时提供容量信息
  • Map()也可以预分配内存来提升性能
func noPreAlloc(size int) {
    data := make([]int, 0)
    for i := 0; i < size; i++{
        data = append(data, i)
    }
}
    func PreAlloc(size int) {
        data := make([]int, 0, size)
        for i := 0; i < size; i++{
            data = append(data, i)
        }
    }
  • 第二点:可以用copy替代re-slice,解决大内存不释放的问题
func getLastBySlice(origin []int) []int {
    return origin[len(origin)-2:]
}
func getLastByCopy(origin []int) []int {
    result := make([]int, 2)
    result = origin[len(origin)-2:]
    return result
}
  1. 字符串的三种处理方式
  • 字符串在GO语言中是不可变类型,占用内存大小是固定的。
  • ①使用 “+” 号来实现字符串拼接方式
// 使用 + 每次都会重新分配内存
func Plus(n int, str string) string {
    s := ""
    for i := 0; i < n; i++ {
        s += str
    }
    return s
}
  • 使用strings.Builder
// Builder和Buffer底层都是Bytes[]数组,使用的是内存扩容策略
// Builder将底层的[]byte直接转换为字符串类型返回
func StrBuilder(n int, str string) string {
    var builder strings.Builder
    for i := 0; i < n; i++ {
        builder.WriteString(str)
    }
    return builder.String()
}
  • 使用bytes.Buffer
// Bufffer转换为字符串时从新申请一块空间
func ByteBuffer(n int, str string) string {
    buf := new(bytes.Buffer)
    for i := 0; i < n; i++ {
        builder.WriteString(str)
    }
    return buf.String()
}
  • 空结构体不占内存,实现set时可以考虑使用map来替代

性能分析工具pprof

  • 程序所耗费的CPU与MEMORY的可视化分析工具 项目案例地址:(https://github.com/wolfogre/go-pprof-practice)

  • 使用命令查看CPU状态 go tool pprof "http://127.0.0.1:6060/debug/pprof/profile?seconds=10"

  • 可视化界面查看CPU性能 go tool pprof -http=:8080 "http://127.0.0.1:6060/debug/pprof/heap

  • 展示view top:flat表示当前函数本身的执行耗时;cum表示当前函数本身加上其调用函数的总耗时。

,调用图:Graph,火焰图:FlameGraphpeek,源码:Source,反汇编:Disassemble

  • 采样Sample CPU,堆内存:Heap,协程goroutine,锁:mutex,阻塞:Block,线程创建:ThreadCreate