io.WriteString()分析

问题

内存管理在Golang中是棘手的,我们可能相信golang本身已具备内存自动管理功能,可以从此解放出来。但上周的某个功能测试结果让我改变了这个看法。问题可以描述为"预期分配8G内存,但实际程序运行过程中分配了12G多,相当于多分配了50%的内存,为何内存会多分配"

经过排查,具体原因是求md5值时使用了**io.WriteString()**函数,而没有使用md5.Write()

func main() {
    hash := md5.New()
    io.WriteString(hash, "ABC")
    hash.Sum(nil)
    //hash.Write([]byte("ABC"))
}

进入io.WriteString(),最终调用hash.Write()。于是百思不得其解,为何最终调用的是同一个函数,但一个分配了内存。想string to byte 是否会分配内存

StringToByte分析

#demo.go
package demo

func StringToByte(s string) []byte {
    return []byte(s)
}
#demo_test.go

package demo

import (
    "testing"
)

func BenchmarkStringToByte(b *testing.B) {
    str := "ABC"
    //for i := 1; i < 1*11; i++ {
    //    str += "ABC"
    //}
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        StringToByte(str)
    }
}

测试时,并没有发现会分配内存。(此时golang中的string和slice结构作了分析),实现上string到slice也的确可以不分配内存

于是分析string到byte转换源码。这里需注意到golang的string类型是不能被改变的,好处是并发场景下可以不加锁的多次使用同一字符串而不用担心安全问题

32字节是string和slicebyte转换的临界分配内存值。

实际到这里也已找到问题原因和解决方法,但性能测试时使用了io.WriteString(),发现即使参数是"ABC",也会分配3个字节,于是疑惑

io.WriteString()

分析结果是动态调用,显示类型转换会分配临时内存

Resources

IO