1
Một số ví dụ về rò rỉ bộ nhớ và cách phòng tránh trong C/C++ là gì?
1
Hiếu Nghĩa10 đã đăng:

Chào các bạn.

Mình có thắc mắc là trong khi viết mã nguồn thực tế, rò rỉ bộ nhớ sẽ xảy ra khi nào và cách phòng tránh trường hợp đó vậy ạ? Làm ơn minh họa câu nói của bạn bằng đoạn mã nguồn thực tế nhé.

Xin cảm ơn các bạn.

thêm bình luận...
1
minhkiet150 đã đăng:

Về cơ bản, khi bạn cấp phát bộ nhớ cho con trỏ trong C/C++, thì bộ nhớ Heap sẽ đảm nhiệm việc này, mà một đặc điểm quan trọng của bộ nhớ Heap đó là đối tượng được cấp phát bởi bộ nhớ Heap không thể tự giải phóng sau khi kết thúc chương trình, do đó, một trong những lỗi phổ biến nhất tạo ra rò rỉ bộ nhớ trong C/C++ là bạn quên giải phóng vùng nhớ đã cấp phát đi, tức là nếu thể hiện bằng ngôn ngữ lập trình bạn quên thêm câu lệnh free (trong C) hoặc delete (trong C++) để giải phóng vùng nhớ.

Vậy một số trường hợp có thể xảy ra rò rỉ bộ nhớ khi viết mã nguồn là,

Quên giải phóng vùng nhớ sau khi cấp phát

Đây là một trong những lỗi rất rất phổ biến, bạn nên luôn nhớ rằng nếu có malloc/calloc/realloc thì phải có free, nếu có new thì phải có delete.

int *A = new int[10]; // Tạo 40 bytes vùng nhớ cho 10 giá trị kiểu số nguyên (1 int = 4 bytes)
delete [] A; // Giải phóng 40 bytes đã cấp phát, giả sử bạn quên câu lệnh này => rò rỉ bộ nhớ.

Có giải phóng vùng nhớ nhưng sai cú pháp

Bạn không nên nhầm lần giữa giải phóng chỉ 1 đối tượng và giải phóng một mảng các phần tử, sự khác biệt giữa chúng là dấu ngoặc vuông [],

delete A; // Giải phóng chỉ một đối tượng A
delete []A; //Giải phóng cả một mảng A

Ví dụ trường hợp tạo nên rò rỉ bộ nhớ khi bạn quên không phân biệt giữa đối tượng và mảng,

// Trường hợp mảng
int *A = new int[10];
delete A; // Sai
delete []A; // Đúng, vì A là mảng chứa 10 phần tử

// Trường hợp 1 đối tượng
int *A = new int; // Chú ý dòng lệnh này, chỉ có 1 đối tượng A duy nhất
delete A; // Đúng
delete []A; // Có thể chấp nhận được, nhưng không rõ ràng, gây phân vân cho người đọc mã nguồn

Cấp phát lại vùng nhớ sau khi đã cấp phát

Hãy nhớ rằng bạn nên giải phóng vùng nhớ của một con trỏ trước khi bạn cấp phát lại vùng nhớ mới cho nó, ví dụ,

int *A = new int[10]; // Cấp phát vùng nhớ cho A chứa 10 số nguyên
delete []A; // Phải giải phóng A trước khi cấp phát lại vùng nhớ mới
A = new int[20]; // Cấp phát vùng nhớ mới cho A có khả năng chứa 20 số nguyên
delete []A; // Giải phóng sau khi sử dụng

Cấp phát vùng nhớ cho con trỏ cục bộ

Bạn không nên nhầm lẫn giữa biến cục bộ và con trỏ cục bộ, vùng nhớ cấp phát cho biến cục bộ nằm trong bộ nhớ Stack và tự động hủy sau khi hàm kết thúc, trong khi vùng nhớ của con trỏ cục bộ thì không, nó vẫn nằm đó trong bộ nhớ Heap mặc dù hàm của bạn đã thực hiện xong công việc.

int someFunction() {
    int *A = new int[10]; // Khởi tạo mảng A nằm trong hàm someFunction
    // .....
   delete []A; // Nhớ phải giải phóng vùng nhớ sau khi sử dụng
}

Đó là tất cả những gì mình biết, hy vọng sẽ có ích.

đã bổ sung 3.3 năm trước bởi
Avatar: minhkiet minhkiet150
thêm bình luận...
Bạn đang thắc mắc? Ghi câu hỏi của bạn và đăng ở chế độ cộng đồng (?)