fix(pool): use pointer types in sync.Pool to avoid boxing
Change sync.Pool to store *[]byte instead of []byte to prevent interface boxing allocation on each Get/Put operation. Applied to: - cmd/portal-tunnel/main.go - cmd/relay-server/manager/bps_manager.go - portal/utils/ratelimit/bucket.go
cognitive committed
Dec 30, 2025 at 00:22 UTC
a0288ca8e5544c6b369a9f4ac94e046c40dfb85a
3 files changed
+23
-11
cmd/portal-tunnel/main.go
+9
-5
@@ -19,8 +19,12 @@ import (
19
20
// bufferPool provides reusable 64KB buffers for io.CopyBuffer to eliminate
21
// per-copy allocations and reduce GC pressure under high concurrency.
22
+// Using *[]byte to avoid interface boxing allocation in sync.Pool.
23
var bufferPool = sync.Pool{
23
- New: func() any { return make([]byte, 64*1024) },
24
+ New: func() any {
25
+ b := make([]byte, 64*1024)
26
+ return &b
27
+ },
28
}
29
30
type Config struct {
@@ -200,15 +204,15 @@ func proxyConnection(ctx context.Context, localAddr string, relayConn net.Conn)
204
}()
205
206
go func() {
203
- buf := bufferPool.Get().([]byte)
204
- defer bufferPool.Put(buf)
207
+ buf := *bufferPool.Get().(*[]byte)
208
+ defer bufferPool.Put(&buf)
209
_, err := io.CopyBuffer(localConn, relayConn, buf)
210
errCh <- err
211
}()
212
213
go func() {
210
- buf := bufferPool.Get().([]byte)
211
- defer bufferPool.Put(buf)
214
+ buf := *bufferPool.Get().(*[]byte)
215
+ defer bufferPool.Put(&buf)
216
_, err := io.CopyBuffer(relayConn, localConn, buf)
217
errCh <- err
218
}()
cmd/relay-server/manager/bps_manager.go
+7
-3
@@ -331,7 +331,11 @@ func (b *Bucket) Stats() (totalBytes, throttleHits int64, totalWaited time.Durat
331
}
332
333
// internal buffer pool for Copy - 64KB reduces Take() call frequency and lock contention
334
-var bufPool = sync.Pool{New: func() any { return make([]byte, 64*1024) }}
334
+// Using *[]byte to avoid interface boxing allocation in sync.Pool.
335
+var bufPool = sync.Pool{New: func() any {
336
+ b := make([]byte, 64*1024)
337
+ return &b
338
+}}
339
340
// Copy copies from src to dst, enforcing the provided byte-rate bucket if not nil.
341
// Multiple Copy calls sharing the same bucket will fairly share the bandwidth.
@@ -340,8 +344,8 @@ func Copy(dst io.Writer, src io.Reader, b *Bucket) (int64, error) {
344
if b == nil {
345
return io.Copy(dst, src)
346
}
343
- buf := bufPool.Get().([]byte)
344
- defer bufPool.Put(buf)
347
+ buf := *bufPool.Get().(*[]byte)
348
+ defer bufPool.Put(&buf)
349
350
var total int64
351
startTime := time.Now()
portal/utils/ratelimit/bucket.go
+7
-3
@@ -59,7 +59,11 @@ func (b *Bucket) Take(n int64) {
59
}
60
61
// internal buffer pool for Copy
62
-var bufPool = sync.Pool{New: func() any { return make([]byte, 64*1024) }}
62
+// Using *[]byte to avoid interface boxing allocation in sync.Pool.
63
+var bufPool = sync.Pool{New: func() any {
64
+ b := make([]byte, 64*1024)
65
+ return &b
66
+}}
67
68
// Copy copies from src to dst, enforcing the provided byte-rate bucket if not nil.
69
// Returns bytes written and any copy error encountered.
@@ -67,8 +71,8 @@ func Copy(dst io.Writer, src io.Reader, b *Bucket) (int64, error) {
71
if b == nil {
72
return io.Copy(dst, src)
73
}
70
- buf := bufPool.Get().([]byte)
71
- defer bufPool.Put(buf)
74
+ buf := *bufPool.Get().(*[]byte)
75
+ defer bufPool.Put(&buf)
76
77
var total int64
78
for {