From c136f72a011fc48b001cd449f4301c65f6f1b935 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 5 Oct 2018 18:45:18 -0700 Subject: [PATCH] pool pointers to pointers So, creating interfaces *allocates*. That means `pool.Put([]byte)` allocates, that's obviously bad. This was, unfortunately, showing up in go-ipfs after switching to a pool-backed yamux. What's the solution to too many allocations? More object pools! --- pool.go | 22 +++++++++++++++++++--- pool_test.go | 16 ++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/pool.go b/pool.go index e483a4e..d812840 100644 --- a/pool.go +++ b/pool.go @@ -41,6 +41,11 @@ const MaxLength = math.MaxInt32 // You MUST NOT copy Pool after using. type BufferPool struct { pools [32]sync.Pool // a list of singlePools + ptrs sync.Pool +} + +type bufp struct { + buf []byte } // Get retrieves a buffer of the appropriate length from the buffer pool or @@ -57,8 +62,12 @@ func (p *BufferPool) Get(length int) []byte { return make([]byte, length) } idx := nextLogBase2(uint32(length)) - if buf := p.pools[idx].Get(); buf != nil { - return buf.([]byte)[:uint32(length)] + if ptr := p.pools[idx].Get(); ptr != nil { + bp := ptr.(*bufp) + buf := bp.buf[:uint32(length)] + bp.buf = nil + p.ptrs.Put(ptr) + return buf } return make([]byte, 1< 100 { + t.Fatalf("expected less than 100 frees after GC, got %d", frees) + } +} + func TestPool(t *testing.T) { // disable GC so we can control when it happens. defer debug.SetGCPercent(debug.SetGCPercent(-1)) -- GitLab