Có hai nơi mà các biến có thể được đưa vào bộ nhớ. Khi bạn tạo một biến như thế này:
int a;
char c;
char d[16];
Các biến được tạo trong " ngăn xếp ". Các biến ngăn xếp tự động được giải phóng khi chúng vượt ra khỏi phạm vi (nghĩa là khi mã không thể tiếp cận chúng nữa). Bạn có thể nghe thấy chúng được gọi là biến "tự động", nhưng điều đó đã không còn hợp thời.
Nhiều ví dụ mới bắt đầu sẽ chỉ sử dụng các biến ngăn xếp.
Ngăn xếp rất hay vì nó tự động, nhưng nó cũng có hai nhược điểm: (1) Trình biên dịch cần biết trước độ lớn của các biến và (b) không gian ngăn xếp có phần hạn chế. Ví dụ: trong Windows, theo cài đặt mặc định cho trình liên kết Microsoft, ngăn xếp được đặt thành 1 MB và không phải tất cả đều có sẵn cho các biến của bạn.
Nếu bạn không biết mảng của mình lớn như thế nào tại thời điểm biên dịch, hoặc nếu bạn cần một mảng hoặc cấu trúc lớn, bạn cần "kế hoạch B".
Kế hoạch B được gọi là " đống ". Bạn thường có thể tạo các biến lớn như Hệ điều hành sẽ cho phép bạn, nhưng bạn phải tự làm. Các bài đăng trước đó đã chỉ cho bạn một cách bạn có thể làm, mặc dù có những cách khác:
int size;
// ...
// Set size to some value, based on information available at run-time. Then:
// ...
char *p = (char *)malloc(size);
(Lưu ý rằng các biến trong heap không được thao tác trực tiếp mà thông qua con trỏ)
Khi bạn tạo một biến heap, vấn đề là trình biên dịch không thể biết khi nào bạn hoàn thành với nó, vì vậy bạn mất tính năng tự động phát hành. Đó là nơi "giải phóng thủ công" mà bạn đang đề cập đến. Mã của bạn bây giờ chịu trách nhiệm quyết định khi nào biến không cần thiết nữa và giải phóng nó để bộ nhớ có thể được sử dụng cho các mục đích khác. Đối với trường hợp trên, với:
free(p);
Điều làm cho lựa chọn thứ hai này trở thành "công việc kinh doanh khó chịu" là không phải lúc nào bạn cũng dễ dàng biết được khi nào biến số không cần thiết nữa. Quên phát hành một biến khi bạn không cần đến nó sẽ khiến chương trình của bạn sử dụng nhiều bộ nhớ hơn mà nó cần. Tình trạng này được gọi là "rò rỉ". Bộ nhớ "bị rò rỉ" không thể được sử dụng cho bất cứ điều gì cho đến khi chương trình của bạn kết thúc và hệ điều hành khôi phục tất cả tài nguyên của nó. Thậm chí có thể xảy ra các vấn đề tồi tệ hơn nếu bạn phát hành một biến đống do nhầm lẫn trước khi bạn thực sự xử lý xong.
Trong C và C ++, bạn có trách nhiệm dọn dẹp các biến đống của mình như được hiển thị ở trên. Tuy nhiên, có những ngôn ngữ và môi trường như ngôn ngữ Java và .NET như C # sử dụng một cách tiếp cận khác, trong đó heap được tự dọn dẹp. Phương pháp thứ hai này, được gọi là "thu gom rác", dễ dàng hơn nhiều đối với nhà phát triển nhưng bạn phải trả một khoản phạt về chi phí và hiệu suất. Đó là một sự cân bằng.
(Tôi đã lược qua nhiều chi tiết để đưa ra một câu trả lời đơn giản hơn, nhưng hy vọng rằng câu trả lời ở cấp độ cao hơn)