DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
MediumTheory

Using sync.Pool to Reduce GC Pressure

22 views

Problem Statement

Your JSON API service allocates and discards thousands of byte buffers per second, causing GC pauses. Implement object pooling using sync.Pool to reuse allocations.

What is sync.Pool?

A pool of temporary objects that can be saved and retrieved. Objects may be removed by GC at any time without notification.

Basic Usage

package main

import (
    "bytes"
    "sync"
)

var bufferPool = sync.Pool{
    New: func() interface{} {
        return new(bytes.Buffer)
    },
}

func processRequest(data []byte) []byte {
    // Get buffer from pool
    buf := bufferPool.Get().(*bytes.Buffer)
    
    // Ensure cleanup
    defer func() {
        buf.Reset()
        bufferPool.Put(buf)
    }()
    
    // Use buffer
    buf.Write(data)
    buf.WriteString(" processed")
    
    // Must copy result before returning buffer to pool
    result := make([]byte, buf.Len())
    copy(result, buf.Bytes())
    
    return result
}

Benchmark: With vs Without Pool

func BenchmarkWithoutPool(b *testing.B) {
    for i := 0; i < b.N; i++ {
        buf := new(bytes.Buffer)
        buf.WriteString("hello world")
        _ = buf.Bytes()
    }
}

func BenchmarkWithPool(b *testing.B) {
    pool := sync.Pool{
        New: func() interface{} {
            return new(bytes.Buffer)
        },
    }
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        buf := pool.Get().(*bytes.Buffer)
        buf.WriteString("hello world")
        _ = buf.Bytes()
        buf.Reset()
        pool.Put(buf)
    }
}

// Results:
// BenchmarkWithoutPool-8   5000000   312 ns/op   112 B/op   2 allocs/op
// BenchmarkWithPool-8     20000000    78 ns/op     0 B/op   0 allocs/op

JSON Encoder Pool (Real-World)

package jsonutil

import (
    "bytes"
    "encoding/json"
    "sync"
)

var encoderPool = sync.Pool{
    New: func() interface{} {
        return &encoderBuffer{
            buf: new(bytes.Buffer),
        }
    },
}

type encoderBuffer struct {
    buf *bytes.Buffer
    enc *json.Encoder
}

func Marshal(v interface{}) ([]byte, error) {
    eb := encoderPool.Get().(*encoderBuffer)
    defer func() {
        eb.buf.Reset()
        encoderPool.Put(eb)
    }()
    
    if eb.enc == nil {
        eb.enc = json.NewEncoder(eb.buf)
    }
    
    if err := eb.enc.Encode(v); err != nil {
        return nil, err
    }
    
    // Remove trailing newline from Encode
    result := eb.buf.Bytes()
    if len(result) > 0 && result[len(result)-1] == '\n' {
        result = result[:len(result)-1]
    }
    
    // Copy before returning to pool
    out := make([]byte, len(result))
    copy(out, result)
    return out, nil
}

Pool Lifecycle with GC

func demonstrateGCInteraction() {
    pool := sync.Pool{
        New: func() interface{} {
            fmt.Println("Creating new object")
            return &bytes.Buffer{}
        },
    }
    
    // Put objects in pool
    for i := 0; i < 10; i++ {
        pool.Put(&bytes.Buffer{})
    }
    
    fmt.Println("Before GC - getting from pool:")
    _ = pool.Get() // Retrieves from pool
    
    // Force GC - pool may be cleared
    runtime.GC()
    
    fmt.Println("After GC - getting from pool:")
    _ = pool.Get() // May call New() if pool was cleared
}

Common Mistakes

// ❌ WRONG: Using result after Put
buf := pool.Get().(*bytes.Buffer)
buf.WriteString("data")
result := buf.Bytes() // Points to pooled buffer
pool.Put(buf)
return result // DANGER: result may be corrupted

// ✅ CORRECT: Copy before Put
buf := pool.Get().(*bytes.Buffer)
buf.WriteString("data")
result := make([]byte, buf.Len())
copy(result, buf.Bytes())
pool.Put(buf)
return result

Follow-up Questions

  1. Why doesn't sync.Pool have a Size() method?
  2. When would sync.Pool hurt performance?
  3. How does sync.Pool interact with GOMAXPROCS?

Sample Test Cases

Case 1
Input
pool.Get() when empty
Expected Output
Calls New function to create object
Case 2
Input
pool.Put(obj)
Expected Output
Returns object to pool for reuse

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
22
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go