stack vs heap

Giải thích sự khác biệt giữa Stack vs Heap trong ngữ cảnh Go (Golang) dưới góc nhìn của một Senior Developer:


🧠 Stack vs Heap trong Go

Thuộc tính
Stack
Heap

Mục đích

Lưu trữ biến cục bộ, ngắn hạn

Lưu trữ biến dài hạn, được tham chiếu

Quản lý

LIFO (Last In First Out), tự động

Do GC quản lý (tự động dọn dẹp)

Hiệu năng

Rất nhanh (allocation/freeing)

Chậm hơn do phải GC

Vùng nhớ

Liên tục, nhỏ gọn

Rời rạc, lớn hơn

GC can thiệp?

Không

Escape to heap?

Không

Có – khi biến vượt ra khỏi phạm vi stack


📌 Khi nào biến "escape to heap"?

Go có Escape Analysis – compiler sẽ quyết định biến nên nằm ở stack hay heap.

Ví dụ:

func newPointer() *int {
    x := 10       // biến x sẽ bị "escape to heap"
    return &x     // vì nó được trả về, sống lâu hơn hàm newPointer()
}
func noEscape() int {
    x := 10       // nằm ở stack, không escape
    return x
}

Bạn có thể kiểm tra bằng lệnh:

go build -gcflags="-m" main.go

Nó sẽ in thông tin escape như:

main.go:5:10: moved to heap: x

🚀 Tại sao quan trọng?

  • Performance: stack allocation cực kỳ nhanh, không cần GC.

  • Memory footprint: heap có thể gây fragmentation, cần GC -> ảnh hưởng latency.

  • Tối ưu code: biết khi nào biến escape giúp bạn viết code perform hơn.


✅ Mẹo tối ưu stack/heap trong Go

Tình huống
Khuyến nghị

Tránh trả về con trỏ đến biến local

Sẽ bị escape

Tránh closure giữ biến ngoài phạm vi

Closure làm biến escape

Dùng sync.Pool để reuse object lớn tránh GC

Ưu tiên giá trị (struct) thay vì con trỏ nếu không cần mutable


📚 Bonus: Stack size của Goroutine?

  • Mỗi Goroutine bắt đầu với 2KB stack.

  • Stack của goroutine tự động grow khi cần (khác với thread OS).

  • Điều này giúp Go tạo hàng triệu goroutine mà không tốn RAM như thread truyền thống.


Last updated