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 {