Module 1 — Mô hình bộ nhớ chương trình: tổng quan
Chương trình đang chạy bố trí bộ nhớ thế nào: địa chỉ và con trỏ, stack frame, heap và fragmentation — gốc rễ của stack overflow và rò bộ nhớ.
TL;DR: Khi chương trình chạy, OS cấp cho nó một không gian bộ nhớ và chia thành các vùng có vai trò khác nhau: stack (biến cục bộ, lời gọi hàm — tự dọn), heap (dữ liệu cấp phát động — bạn hoặc runtime dọn), và static (biến toàn cục, hằng — sống suốt đời chương trình). Mọi biến đều nằm tại một địa chỉ, và con trỏ chỉ là một biến lưu địa chỉ đó. Hiểu mô hình này, bạn sẽ thôi bối rối khi gặp StackOverflowError, OutOfMemoryError, hay khi một object tưởng đã "xong việc" vẫn ngốn RAM.
Vì sao module này tồn tại
Bạn đã thấy StackOverflowError khi viết một hàm đệ quy quên điều kiện dừng. Bạn đã thấy chương trình Java ăn vài GB RAM rồi OutOfMemoryError dù bạn "không tạo gì nhiều". Bạn đã đọc code C với *ptr và &x mà không thật sự hình dung chúng làm gì. Ba điều này có chung một gốc: bạn chưa có mô hình rõ ràng về cách chương trình sắp xếp bộ nhớ khi chạy.
Module này không bắt bạn học thuộc "stack lớn lên xuống dưới, heap lớn lên trên". Nó dạy cơ chế: vì sao stack nhanh và tự dọn, vì sao heap linh hoạt nhưng tốn kém, vì sao con trỏ vừa mạnh vừa nguy hiểm, và làm thế nào để chọn đúng vùng nhớ cho dữ liệu của bạn.
Sau module này bạn sẽ
- Explain một địa chỉ bộ nhớ là gì và vì sao mọi biến đều có địa chỉ — kể cả trong ngôn ngữ "không có con trỏ" như Java hay Python.
- Trace cách một stack frame được tạo khi gọi hàm và huỷ khi hàm trả về, và vì sao đệ quy quá sâu gây stack overflow.
- Explain vì sao heap cần cấp phát động, fragmentation là gì, và vì sao cấp phát trên heap chậm hơn stack.
- Choose vùng nhớ đúng (stack, heap, static) cho từng loại dữ liệu và giải thích trade-off về tốc độ, vòng đời và an toàn.
Lộ trình module
Bài 01 đặt nền: địa chỉ bộ nhớ và con trỏ — khái niệm gốc mà mọi thứ còn lại xây trên đó. Bài 02 dùng địa chỉ để giải thích stack: cách mỗi lời gọi hàm đẩy một frame, cách biến cục bộ sống và chết theo frame, và vì sao đệ quy quá sâu làm tràn stack. Bài 03 chuyển sang heap: vì sao cần cấp phát động khi không biết trước kích thước, allocator hoạt động ra sao, và fragmentation làm chậm hoặc cạn bộ nhớ thế nào. Bài 04 tổng hợp: đặt stack, heap và static cạnh nhau, và rút ra quy tắc chọn vùng nhớ. Bài 05 là cheat sheet để bookmark.
Trình tự bottom-up có chủ đích: không hiểu địa chỉ thì không hiểu stack frame; không hiểu stack và heap thì không so sánh được chúng.
Bản đồ 4 bài, đi từ địa chỉ tới quyết định chọn vùng nhớ:
flowchart LR A["01 Dia chi va con tro"] --> B["02 Stack va stack frame"] A --> C["03 Heap va cap phat dong"] B --> D["04 Stack vs heap vs static"] C --> D
Yêu cầu trước khi bắt đầu
- Hoàn thành Course 1 — Dữ liệu & CPU, hoặc đã giải thích được bit/byte là gì và cách CPU đọc-ghi bộ nhớ (mô hình von Neumann).
- Biết lập trình cơ bản bằng một ngôn ngữ bất kỳ (đọc được hàm, biến, vòng lặp, đệ quy).
- Không cần biết C — module dùng pseudocode và đối chiếu Java/Python/Go khi cần.
Time budget
- Module: ~1.3 giờ đọc.
| Bài | Chủ đề | Phút |
|---|---|---|
| 01 | Địa chỉ bộ nhớ và con trỏ | 16 |
| 02 | Stack và stack frame | 18 |
| 03 | Heap và cấp phát động | 18 |
| 04 | Stack vs heap vs static | 15 |
| 05 | Tổng kết & cheat sheet | 12 |
Cách học module này hiệu quả
- Vẽ ra giấy. Mỗi khi đọc một ví dụ gọi hàm, tự vẽ stack với các frame chồng lên nhau. Bộ nhớ là không gian — vẽ giúp bạn "thấy" nó.
- Chạy thử với debugger. Đặt breakpoint trong một hàm đệ quy và xem call stack lớn dần trong IDE. Đó chính là stack bạn đang học.
- Đừng bỏ qua khối "Áp dụng vào code của bạn" cuối mỗi bài — đó là chỗ mô hình bộ nhớ biến thành quyết định thiết kế thật.
Bài tiếp theo: Địa chỉ bộ nhớ và con trỏ
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên