Backend Development 13 min read

Go Performance Optimization Techniques: sync.Pool, Map Key Choices, Code Generation, strings.Builder, strconv, and Slice Allocation

This article presents a collection of practical Go performance‑tuning techniques—including reuse of objects with sync.Pool, avoiding pointer‑heavy map keys, generating marshal code to bypass reflection, using strings.Builder for efficient concatenation, preferring strconv over fmt, and pre‑allocating slices—to significantly reduce allocation overhead and garbage‑collection time.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Go Performance Optimization Techniques: sync.Pool, Map Key Choices, Code Generation, strings.Builder, strconv, and Slice Allocation

Before applying any changes, establish a baseline benchmark using pprof or custom tests to measure current performance.

1. Reuse allocated objects with sync.Pool

The pool provides a free list that can recycle previously allocated structures, reducing allocation and GC pressure. Example:

var bufpool = sync.Pool{
    New: func() interface{} {
        buf := make([]byte, 512)
        return &buf
    },
}

bp := bufpool.Get().(*[]byte)
b := *bp
defer func() {
    *bp = b
    bufpool.Put(bp)
}()
buf := bytes.NewBuffer(b)

When pooling objects that contain fields, reset them before returning to the pool to avoid leaking stale data.

type AuthenticationResponse struct {
    Token  string
    UserID string
}

func (a *AuthenticationResponse) reset() {
    a.Token = ""
    a.UserID = ""
}

rsp := authPool.Get().(*AuthenticationResponse)
defer func() {
    rsp.reset()
    authPool.Put(rsp)
}()

2. Avoid using pointer‑heavy keys in large maps

GC must scan every pointer in a map[string]int . Replacing the string key with an integer reduces scanning overhead. Example comparison shows GC time dropping from ~100 ms to ~4 ms when switching to map[int]int .

var foo = map[string]int{}
// populate foo with 10,000,000 entries
// ...
// GC timing code

Resulting GC times improve dramatically after the change.

3. Generate marshal code to avoid runtime reflection

Using code generators like easyjson creates type‑specific marshal/unmarshal functions that implement the json.Marshaller interface, eliminating the reflection overhead of json.Marshal and json.Unmarshal .

easyjson -all $file.go

This produces $file_easyjson.go with optimized functions.

4. Build strings with strings.Builder

Strings are immutable; concatenating them repeatedly allocates new memory. strings.Builder writes to an internal byte buffer and creates the final string only once. Benchmarks show a 4.7× speedup and an 8× reduction in allocations.

func buildStrNaive() string {
    var s string
    for _, v := range strs { s += v }
    return s
}

func buildStrBuilder() string {
    var b strings.Builder
    b.Grow(60)
    for _, v := range strs { b.WriteString(v) }
    return b.String()
}

5. Prefer strconv over fmt for numeric‑to‑string conversion

Benchmarks demonstrate that strconv.Itoa is about 3.5× faster and allocates fewer bytes than fmt.Sprintf for simple integer formatting.

func strconvFmt(a string, b int) string { return a + ":" + strconv.Itoa(b) }
func fmtFmt(a string, b int) string { return fmt.Sprintf("%s:%d", a, b) }

6. Pre‑allocate slice capacity with make

Creating a slice with zero capacity causes repeated allocations as elements are appended. Using make([]T, 0, expectedLen) allocates the needed backing array once, avoiding extra copies and allocations.

userIDs := make([]string, 0, len(rsp.Users))
for _, u := range rsp.Users { userIDs = append(userIDs, u.ID) }

7. Use APIs that accept byte slices

Methods like time.AppendFormat allow reusing a pre‑allocated buffer, reducing temporary allocations compared to functions that return new strings.

Conclusion

Applying these techniques—object pooling, pointer‑light data structures, code generation, efficient string building, low‑level conversion functions, and careful slice allocation—can dramatically improve Go program performance and reduce garbage‑collector overhead, leading to faster, more scalable services.

PerformanceGomap optimizationsync.Poolslice allocationstrconvstrings.Builder
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.