Skip to content

Commit 8ab0c82

Browse files
authored
mem: Avoid clearing new buffers and clear buffers from simpleBufferPools (#8670)
RELEASE NOTES: * mem: * Avoid clearing buffers which newly allocated. * Clear large buffers (> 1MB) before re-using.
1 parent 7f0fc41 commit 8ab0c82

File tree

2 files changed

+41
-24
lines changed

2 files changed

+41
-24
lines changed

mem/buffer_pool.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ type sizedBufferPool struct {
118118
}
119119

120120
func (p *sizedBufferPool) Get(size int) *[]byte {
121-
buf := p.pool.Get().(*[]byte)
121+
buf, ok := p.pool.Get().(*[]byte)
122+
if !ok {
123+
buf := make([]byte, size, p.defaultSize)
124+
return &buf
125+
}
122126
b := *buf
123127
clear(b[:cap(b)])
124128
*buf = b[:size]
@@ -137,12 +141,6 @@ func (p *sizedBufferPool) Put(buf *[]byte) {
137141

138142
func newSizedBufferPool(size int) *sizedBufferPool {
139143
return &sizedBufferPool{
140-
pool: sync.Pool{
141-
New: func() any {
142-
buf := make([]byte, size)
143-
return &buf
144-
},
145-
},
146144
defaultSize: size,
147145
}
148146
}
@@ -160,6 +158,7 @@ type simpleBufferPool struct {
160158
func (p *simpleBufferPool) Get(size int) *[]byte {
161159
bs, ok := p.pool.Get().(*[]byte)
162160
if ok && cap(*bs) >= size {
161+
clear((*bs)[:cap(*bs)])
163162
*bs = (*bs)[:size]
164163
return bs
165164
}

mem/buffer_pool_test.go

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,44 @@ func (s) TestBufferPool(t *testing.T) {
4949
}
5050

5151
func (s) TestBufferPoolClears(t *testing.T) {
52-
pool := mem.NewTieredBufferPool(4)
52+
const poolSize = 4
53+
pool := mem.NewTieredBufferPool(poolSize)
54+
tests := []struct {
55+
name string
56+
bufferSize int
57+
}{
58+
{
59+
name: "sized_buffer_pool",
60+
bufferSize: poolSize,
61+
},
62+
{
63+
name: "simple_buffer_pool",
64+
bufferSize: poolSize + 1,
65+
},
66+
}
5367

54-
for {
55-
buf1 := pool.Get(4)
56-
copy(*buf1, "1234")
57-
pool.Put(buf1)
68+
for _, tc := range tests {
69+
t.Run(tc.name, func(t *testing.T) {
70+
for {
71+
buf1 := pool.Get(tc.bufferSize)
72+
copy(*buf1, "1234")
73+
pool.Put(buf1)
5874

59-
buf2 := pool.Get(4)
60-
if unsafe.SliceData(*buf1) != unsafe.SliceData(*buf2) {
61-
pool.Put(buf2)
62-
// This test is only relevant if a buffer is reused, otherwise try again. This
63-
// can happen if a GC pause happens between putting the buffer back in the pool
64-
// and getting a new one.
65-
continue
66-
}
75+
buf2 := pool.Get(tc.bufferSize)
76+
if unsafe.SliceData(*buf1) != unsafe.SliceData(*buf2) {
77+
pool.Put(buf2)
78+
// This test is only relevant if a buffer is reused, otherwise try again. This
79+
// can happen if a GC pause happens between putting the buffer back in the pool
80+
// and getting a new one.
81+
continue
82+
}
6783

68-
if !bytes.Equal(*buf1, make([]byte, 4)) {
69-
t.Fatalf("buffer not cleared")
70-
}
71-
break
84+
if !bytes.Equal(*buf1, make([]byte, tc.bufferSize)) {
85+
t.Fatalf("buffer not cleared")
86+
}
87+
break
88+
}
89+
})
7290
}
7391
}
7492

0 commit comments

Comments
 (0)