Reduce GC
Trả lời với góc nhìn của Senior Golang Developer, câu hỏi:
❓ "What are some strategies to reduce GC (Garbage Collection) overhead?"
Đây là vấn đề tối ưu hiệu năng cấp thấp, cực kỳ quan trọng khi xây dựng high-performance backend systems, đặc biệt là service throughput cao và low-latency (như trong game servers, pub/sub, hoặc real-time analytics).
✅ 1. Giảm allocation - "Don’t feed the GC"
GC chỉ phải làm việc nhiều nếu bạn tạo nhiều rác (allocations → garbage).
Chiến lược:
Tránh tạo object ngắn sống nhiều lần bên trong loop.
Tái sử dụng struct hoặc slice thay vì luôn tạo mới.
// BAD: allocates every time
for i := 0; i < 1000; i++ {
b := make([]byte, 1024)
doSomething(b)
}
// GOOD: reuse
buf := make([]byte, 1024)
for i := 0; i < 1000; i++ {
doSomething(buf)
}
✅ 2. Sử dụng sync.Pool
để tái sử dụng object
sync.Pool
để tái sử dụng objectsync.Pool
là một object pool dùng để cache object tạm thời.
var bufPool = sync.Pool{
New: func() any {
return make([]byte, 1024)
},
}
b := bufPool.Get().([]byte)
defer bufPool.Put(b)
Dùng khi bạn có object lớn, tạm thời, dùng nhiều lần. Tránh alloc liên tục.
✅ 3. Tránh tạo string không cần thiết
Golang string
là immutable, mọi thao tác tạo string mới = allocation.
Hạn chế
fmt.Sprintf
hoặcstring([]byte)
nhiều lần.Dùng
strings.Builder
khi cần build string lớn.
✅ 4. Giảm con trỏ không cần thiết
Struct có con trỏ (*T
) hoặc field dạng con trỏ sẽ phải quản lý bởi GC.
type Person struct {
Name string // GOOD
Age int // GOOD
}
type Bad struct {
Name *string // BAD – GC phải scan & mark
}
Dùng giá trị trực tiếp thay vì con trỏ nếu không cần nullable.
✅ 5. Tối ưu slice & map
Slice: Preallocate capacity khi có thể.
Map: Dùng
make(map[T]V, capacity)
để tránh rehash liên tục.Tránh tạo map tạm thời ngắn hạn lặp đi lặp lại.
✅ 6. Tối ưu lifetime object – Escape Analysis
Biến nằm trong stack thì GC không cần quản lý (free ngay khi hàm return).
Chiến lược:
Tránh return con trỏ đến local struct.
Tránh dùng interface khiến giá trị bị “escape” ra heap.
func newUser() *User { // This escapes to heap
return &User{Name: "Tài"}
}
✅ 7. Giảm áp lực GC bằng cách scale horizontal
Phân tán workload sang nhiều instance → GC mỗi process nhẹ hơn.
Thường dùng trong system chịu tải nặng (microservices, load balancing).
✅ 8. Dùng -gcflags
và profiling để tune GC
-gcflags
và profiling để tune GCGODEBUG=gctrace=1
→ để xem log GC.Dùng
pprof
để xem số lần GC, memory allocated.Flag build:
go build -gcflags "-m"
để xem biến nào escape to heap.
✅ 9. Tránh tạo closure trong loop nếu không cần
Closure thường làm biến bị escape to heap nếu không tối ưu.
for i := 0; i < 10; i++ {
go func() { fmt.Println(i) }() // BAD: i captured
}
✅ 10. Sử dụng Arena (Go 1.22 experimental)
Go 1.22 giới thiệu arena allocation (tạm thời). Dùng cho batch jobs mà bạn có thể free toàn bộ một khối memory cùng lúc (manual memory management).
a := arena.New()
defer a.Free()
b := arena.MakeSlice[byte](a, 100)
⚠️ Experimental – chưa production-stable nhưng tương lai có thể thay đổi game cho hiệu năng.
🧠 Kết luận:
Giảm rác (garbage)
Hạn chế allocation, reuse object
Giảm tần suất GC
Dùng sync.Pool, preallocate slice/map
Giảm thời gian stop-the-world
Tránh pointer không cần thiết, dùng value types
Giám sát và tuning
Dùng pprof
, GODEBUG
, escape analysis
Last updated