Chắc hẳn nhiều người đã từng bị hiện tượng ứng dụng của mình bị crash khi đệ quy quá nhiều lần hoặc đệ quy vô hạn. Đây là một bài viết giải thích tại sao ứng dụng bị crash dưới góc độ kĩ thuật.
Chúng ta bắt đầu!
1. Stack frame
Có thể hiểu đơn giản stack frame là một vùng nhớ (đơn vị của stack) của stack. Nó chứa dữ liệu của mỗi lần gọi hàm. Mỗi một function call thì sẽ tạo thành một stackframe và khi hàm đó được gọi xong thì stack frame đó sẽ bị huỷ.
2. Stack frame có chứa gì
Khi function call, hàm cha sẽ truyền các tham số của hàm vào stack frame của hàm con, hàm con cũng khởi tạo các biến cục bộ của mình trên stack frame này.
Tóm váy lại là stack frame chứa:
- Tham số truyền vào của hàm.
- Biến cục bộ.
3. Tại sao stack bị tràn
Stack là một vùng nhớ rất nhỏ, nó không lớn như heap. Nó chỉ được dùng để lưu trữ các giá trị trong lúc function call. Thế nên nó rất dễ bị tràn (sử dụng hết) trong quá trình chương trình chạy nếu gọi hàm đệ quy quá nhiều lần.
4. Tại sao không có biến cục bộ hay tham số mà vẫn bị crash
Ta thử chạy chương trình này:
#include <stdio.h> void exe() { exe(); } int main() { exe(); return 0; }
Như mình đã trình bày bên trên, thì stack frame chứa local variable và biến tham số của hàm. Tuy nhiên ngoài nó ra thì chương trình cần phải lưu trữ lại giá trị của thanh ghi rbp
(thanh ghi dùng để xác định đáy của stack) hay thậm trí cả return value
nữa.
Thế nên là mỗi khi gọi hàm exe
thì chương trình đều tạo stackframe và sau đó đẩy rbp và return value vào trong stack frame. Thế nên stack vẫn tốn RAM mỗi khi function call. Thế nên chương trình vẫn crash.