Object pooling helps reduce allocation churn in high-throughput Go programs by reusing objects instead of allocating fresh ones each time. This avoids repeated work for the allocator and eases pressure on the garbage collector, especially when dealing with short-lived or frequently reused structures.
Go's sync.Pool provides a built-in way to implement pooling with minimal code. It's particularly effective for objects that are expensive to allocate or that would otherwise contribute to frequent garbage collection cycles. While not a silver bullet, it's a low-friction tool that can lead to noticeable gains in latency and CPU efficiency under sustained load.
Object pooling allows programs to reuse memory by recycling previously allocated objects instead of creating new ones on every use. Rather than hitting the heap each time, objects are retrieved from a shared pool and returned once they're no longer needed. This reduces the number of allocations, cuts down on garbage collection workload, and leads to more predictable performance—especially in workloads with high object churn or tight latency requirements.
package main
import (
"fmt"
"sync"
)
type Data struct {
Value int
}
var dataPool = sync.Pool{
New: func() any {
return &Data{}
},
}
func main() {
for i := 0; i < 1000000; i++ {
obj := dataPool.Get().(*Data) // Retrieve from pool
obj.Value = 42 // Use the object
dataPool.Put(obj) // Return object to pool for reuse
}
fmt.Println("Done")
}Warning
An object retrieved from the pool with Get() will have the exact same state it had when it was returned with Put(). The pool just stores and retrieves pointers; it doesn't clean or reset the objects for you.