benchmem 的输出

Kri*_*ski 8 go performance-testing

使用内存分析器运行基准测试时,我看到以下输出

SomeFunc             100      17768876 ns/op         111 B/op          0 allocs/op
Run Code Online (Sandbox Code Playgroud)

我不明白输出 - 0 allocs/op 但分配了 111 B?知道这意味着什么吗?我的函数是否在堆上分配内存?

icz*_*cza 10

基准测试结果收集在一个 type 值中testing.BenchmarkResult

type BenchmarkResult struct {
        N         int           // The number of iterations.
        T         time.Duration // The total time taken.
        Bytes     int64         // Bytes processed in one iteration.
        MemAllocs uint64        // The total number of memory allocations; added in Go 1.1
        MemBytes  uint64        // The total number of bytes allocated; added in Go 1.1
}
Run Code Online (Sandbox Code Playgroud)

您看到的已分配内存和每个操作的分配值由BencharkResult.AllocedBytesPerOp()and返回BenchmarkResult.AllocsPerOp()。他们记录了返回值是:

AllocedBytesPerOp 返回r.MemBytes / rN

AllocsPerOp 返回r.MemAllocs / rN

所以结果是整数除法。这意味着如果基准函数在不同的调用中执行不同数量的分配,结果可能不是整数,但小数部分会被丢弃(这就是整数除法的工作原理)。

因此,如果函数执行的平均分配少于 1 次,您将看到0 allocs/op,但如果每次调用的平均值至少为 1 个字节,则分配的内存可能大于 0。

让我们看一个例子:

var (
    counter   int
    falseCond bool // Always false at runtime
)

func AvgHalfAllocs() {
    counter++
    if counter%2 == 0 {
        return
    }
    buf := make([]byte, 128)
    if falseCond {
        fmt.Println(buf)
    }
}

func AvgOneAndHalfAllocs() {
    for i := 0; i < 3; i++ {
        AvgHalfAllocs()
    }
}
Run Code Online (Sandbox Code Playgroud)

这里AvgHalfAllocs()平均每个调用进行一半分配,它通过从一半调用返回而不分配任何东西,并在另一半调用中进行 1 次分配。

AvgOneAndHalfAllocs()平均每次调用进行 1.5 次分配,因为它调用了AvgHalfAllocs()3 次。

该的目的falseCond变量和fmt.Println()呼叫只是所以编译器不优化了我们的分配,但fmt.Println()永远不会被调用,因此它不会与分配干扰。

像这样对上述 2 个函数进行基准测试:

func BenchmarkAvgHalfAllocs(b *testing.B) {
    for i := 0; i < b.N; i++ {
        AvgHalfAllocs()
    }
}

func BenchmarkAvgOneAndHalfAllocs(b *testing.B) {
    for i := 0; i < b.N; i++ {
        AvgOneAndHalfAllocs()
    }
}
Run Code Online (Sandbox Code Playgroud)

结果是:

BenchmarkAvgHalfAllocs-4          50000000    29.2 ns/op    64 B/op   0 allocs/op
BenchmarkAvgOneAndHalfAllocs-4    20000000    92.0 ns/op   192 B/op   1 allocs/op
Run Code Online (Sandbox Code Playgroud)

如您所见,0在 的情况下AvgHalfAllocs(),每个调用的 0.5 分配被截断为,而在 的情况下,1.5 被截断为 1 AvgOneAndHalfAllocs()

在这种情况下平均分配的内存AvgHalfAllocs()为 0.5 * 128 字节 = 64 字节。

在这种情况下平均分配的内存AvgOneAndHalfAllocs()为 1.5 * 128 字节 = 192 字节。