Cấp phát bộ nhớ là gì

Một biến muốn sử dụng được cần được khai báo. Khi chạy chương trình và gặp lệnh khai báo thì hệ điều hành sẽ cấp phát vùng nhớ cho biến. Có những cách cấp phát bộ nhớ là:

    • Cấp phát bộ nhớ tĩnh [Static memory allocation]
    • Cấp phát bộ nhớ tự động [Automatic memory allocation]
    • Cấp phát bộ nhớ động [Dynamic memory allocation]

Bài này sẽ giúp các bạn hiểu rõ những cách cấp phát bộ nhớ này. Trong đó, cấp phát bộ nhớ động là một kỹ thuật lập trình rất hay nhưng cũng khá khó hiểu. Nhưng một khi đã hiểu và sử dụng thành thạo nó thì bạn sẽ dễ dàng quản lý bộ nhớ và tối ưu chương trình của mình.

Bộ nhớ ảo và bộ nhớ vật lý

Bộ nhớ vật lý là bộ nhớ RAM. Khi khai báo biến thì cần cấp phát vùng nhớ cho biến. Vùng nhớ của biến được xác định bởi địa chỉ duy nhất. Thực tế, địa chỉ này không phải là địa chỉ vật lý trên RAM mà là địa chỉ trên bộ nhớ ảo. Vậy bộ nhớ ảo là gì?

Bộ nhớ ảo và bộ nhớ vật lý

Bộ nhớ ảo là một kỹ thuật quản lý bộ nhớ được sự hỗ trợ của cả hệ điều hành và CPU. Địa chỉ ô nhớ được sử dụng bởi các chương trình phần mềm là địa chỉ ảo. Hệ điều hành sẽ quản lý những địa chỉ ảo này và có nhiệm vụ xác định địa chỉ ảo nào tương ứng với địa chỉ vật lý nào trên RAM.

 Khi CPU cần xử lý dữ liệu theo yêu cầu của chương trình phần mềm, CPU sẽ tự động chuyển địa chỉ ảo sang địa chỉ vật lý để truy xuất dữ liệu. Đơn vị quản lý bộ nhớ [MMU] là một thiết bị phần cứng được tích hợp vào CPU để làm nhiệm vụ này.

Bộ nhớ ảo được sinh ra nhằm giúp các ứng dụng quản lý vùng bộ nhớ được chia sẻ, tăng độ an toàn cho các vùng nhớ và giúp chương trình sử dụng nhiều bộ nhớ hơn bộ nhớ vật lý hiện có.

Các vùng nhớ của một chương trình khi thực thi

Khi một chương trình được thực thi, những địa chỉ ảo dành cho chương trình đó được chia thành nhiều vùng nhớ khác nhau. Những vùng nhớ đó là:

Code segment là nơi lưu trữ các lệnh của chương trình đã được biên dịch. Các lệnh này có thể dưới dạng mã máy hoặc bytecode.

Data là nơi khởi tạo giá trị cho các biến kiểu static, biến toàn cục [global variable] của chương trình.

BSS dùng để lưu trữ các biến kiểu static, biến toàn cục [global variable] nhưng chưa được khởi tạo giá trị cụ thể.

Heap được sử dụng để cấp phát bộ nhớ thông qua kỹ thuật cấp phát bộ nhớ động [Dynamic memory allocation]. Bộ nhớ sẽ được cấp phát khi chương trình đang thực thi [runtime].

Stack được dùng để cấp phát bộ nhớ thông qua các kỹ thuật:

    • Cấp phát bộ nhớ tĩnh [Static memory allocation]: cấp phát cho biến static và biến toàn cục, được cấp phát lúc biên dịch chương trình.
    • Cấp phát bộ nhớ tự động [Automatic memory allocation]: cấp phát vùng nhớ cho các biến cục bộ và các tham số của hàm, được cấp phát tại thời điểm chương trình đang chạy, khi chương trình đi vào một khối lệnh.

Trong ngôn ngữ C++, các bạn có thể dùng toán tử new delete để cấp phát và giải phóng bộ nhớ động cho các biến cơ bản. Nếu dùng ngôn ngữ C thì các bạn có các hàm malloc[], calloc[], realloc[], free[] để cấp phát và giải phóng bộ nhớ động.

Cấp phát động cho biến với toán tử new

Chức năng của toán tử new: cấp phát bộ nhớ động. Toán tử này trả về một con trỏ trỏ tới địa chỉ ô nhớ đầu tiên của vùng nhớ vừa được cấp phát.

Cú pháp cấp phát bộ nhớ sử dụng new:

= new ;

Ví dụ cấp phát bộ nhớ động chứa một phần tử có kiểu int:

int *p; p= new int;

Trong một số trường hợp, nhiều chương trình đang chạy và máy tính hết bộ nhớ. Lúc này, hệ điều hành không thể cấp phát động khi dùng toán tử new, một con trỏ NULL sẽ được trả về.

Nên kiểm tra xem con trỏ trả về bởi toán tử new có bằng NULL hay không:

int * a; a = new int; if [a == NULL] { //thông báo hết bộ nhớ };

Giải phóng bộ nhớ động của biến với toán tử delete

Bộ nhớ động đã được cấp phát nhưng khi không cần dùng nữa thì cần giải phóng bộ nhớ này. Sử dụng toán tử delete để giải phóng bộ nhớ động đã được cấp phát:

delete ;

Ví dụ:

int *p; p= new int; delete p;

Lưu ý: Giải phóng vùng nhớ 4 byte kiểu int rồi nhưng con trỏ p vẫn trỏ tới ô nhớ có địa chỉ 80024. Ta gọi là “con trỏ lạc”. Nếu sau đó lỡ thao tác với con trỏ p [*p] thì dữ liệu lấy ra được chỉ là giá trị rác hoặc sẽ bị lỗi. Để tránh con trỏ lạc thì gán con trỏ bằng NULL sau khi delete:

int *p; p= new int; delete p; p = NULL;

Chương trình C++ minh họa cấp phát động cho biến

#include using namespace std; int main[] { // declare an int pointer int *pointInt; // declare a float pointer float *pointFloat; // dynamically allocate memory pointInt = new int; pointFloat = new float; // assigning value to the memory *pointInt = 45; *pointFloat = 45.45f; cout

Chủ Đề