Go: bytes: inefficient Buffer.grow algorithm

Created on 4 Dec 2020  路  5Comments  路  Source: golang/go

According to sizeclasses.go, allocating any amount of space greater than the previous size class and below the current size class is inefficient (e.g., allocating 257B is 11% wasteful since it allocates 288B anyways).

The current Buffer.grow algorithm is inefficient since it may choose a buffer size that is in-between size classes, rather than optimally using the entire size class.

For example:

var bb bytes.Buffer
bb.Write(make([]byte, 1<<12))
fmt.Println(cap(bb.Bytes())) // exactly 1<<12
bb.WriteByte('a')
fmt.Println(cap(bb.Bytes())) // exactly (1<<13) + 1, 13.5% waste

While we should avoid teaching Buffer.grow about size classes, it could choose values that align with 2n or 2n+2n-1, which would have a high probability of lying exactly on a type-class boundary.

NeedsInvestigation Performance

Most helpful comment

If buffer.grow would use append+make slice extending idiom to grow it could get that benefit without using sizeclasses: #21266

A size class aware make would also be an option if an addition to the Go language would be accepted: #24204

All 5 comments

Related, for your entertainment: https://commaok.xyz/post/discovering-size-classes/

If buffer.grow would use append+make slice extending idiom to grow it could get that benefit without using sizeclasses: #21266

A size class aware make would also be an option if an addition to the Go language would be accepted: #24204

/cc @bradfitz @ianlancetaylor

If buffer.grow would use append+make slice extending idiom to grow it could get that benefit without using sizeclasses

The current implementation of append has a growth rate that approaches 1.25x as the slice gets larger.
The current implementation of Buffer.grow has a growth rate of 2x.

While a growth rate of 1.25x is more memory efficient, it's probably slower due to the increased number of allocations+copying. Switching the growth rate from 2x to 1.25x seems to be a more substantial change than just addressing the wasted space.

Nevermind, ignore my comment, I just realized an append+make effectively allows you control the growth rate by controlling the size of the make.

Was this page helpful?
0 / 5 - 0 ratings