Giới thiệu về bản chất của Memory leak

Cùng Nhau Học Linux Kernel
Cùng Nhau Học Linux Kernel
24 bài viết — 32 Người theo dõi |
0
2

Theo trào lưu vài ngày một topic ngẫu hứng. Hôm nay mình muốn giới thiệu với các bạn chủ để "Memory leak".

Chắc hẳn trong chúng ta ai chẳng vài ba chục lần gây ra lỗi memory leak trong chương trình. Nhưng các bạn có bao giờ tự hỏi bản chất của việc memory leak là như thế nào không. Trong bài viết này mình sẽ giải thích nó một cách cặn kẽ.

Memory leak xảy ra sau khi chúng ta xin cấp phát bộ nhớ bằng các hàm như calloc hoặc malloc nhưng sau đó chúng ta quên giải phóng nó. Ví dụ như đoạn code sau:
int gay_leak()
{
int *ptr = malloc(1000);
return 0;
}
Trong hàm gay_leak chúng ta xin cấp phát 1000 bytes bộ nhớ. Vùng nhớ đó được trỏ đến thông qua con trỏ ptr. Tuy nhiên trong hàm gay_leak chúng ta không có câu lệnh free vùng nhớ được cấp phát. Sau khi hàm gay_leak kết thúc, biến ptr sẽ được xóa đi tuy nhiên vùng nhớ mà nó đang trỏ đến thì vẫn ở đó. Tuy nhiên lúc đó không có con trỏ nào tham chiếu đến nó cả. Lúc này chúng ta đã gây leak 1000 bytes.

Vậy bản chất phía sau của memory leak là gì. Về cơ bản chúng ta có 2 loại memory leak - 1 là leak không gian địa chỉ bộ nhớ của 1 process và 2 là leak bộ nhớ vật lý.

Quay lại hàm gay_leak. Sau khi hàm malloc return success, thực chất chưa có vùng nhớ vật lý nào được cấp phát cả. Thứ duy nhất được cấp phát là 1 dải địa chỉ virtual address nằm bên trái của bảng process address table (Các bạn có thể đọc bài này để biết process address table là gì: https://www.facebook.com/groups/259967441230713/permalink/326381837922606/). Con trỏ ptr sẽ trỏ vào địa chỉ virtual address đầu tiền của dải địa chỉ đó. Chỉ khi chúng ta truy cập vào dải địa chỉ đó thông qua con trỏ ptr (Ví dụ như: strcpy(ptr, "Hello world");) thì OS mới cấp phát cho chúng ta 1 vùng nhớ thật. Vậy hàm gây leak ở ví dụ đầu sẽ gây ra leak không gian địa chỉ chứ không gây leak vùng nhớ vật lý. Process sẽ bị terminate khi nó dùng hết dải virtual address bộ nhớ của nó. Ví dụ cho hệ thống 32 bit thì mỗi process sẽ có không gian địa chỉ bộ nhớ từ 0 đến 2^32 - 1. Tuy nhiên 1G đầu sẽ dùng để đánh địa chỉ cho kernel-space nên mỗi process sẽ có 3G địa chỉ bộ nhớ cho hàm malloc. Nếu chúng ta cấp phát hết 3G thì process sẽ bị tràn không gian địa chỉ bộ nhớ. Kết quả là OS sẽ gửi terminal signal khiến cho nó bị crash.

Nếu bây giờ mình sửa lại một chút ở hàm gay_leak:
int gay_leak_new()
{
int *ptr = calloc(1000);
return 0;
}
Khi thay câu lệnh malloc bằng calloc thì điều gì sẽ xảy ra? Hàm calloc ngoài việc cấp phát bộ nhớ nó còn memset zero cho vùng nhớ đó. Tức nó ngay sau khi cấp phát nó phải truy cập vào vùng nhớ đó. Kết quả là hàm calloc bắt OS phải cấp phát 1 vùng nhớ vậy lý thật. Trong trường hợp này, hàm gay_leak_new sẽ gây leak vùng nhớ vật lý. Đến khi OS hết vùng nhớ vật lý free thì nó sẽ dừng toàn bộ các hàm malloc memory trong hệ thống. Dẫn đến toàn bộ hệ thống sẽ bị dừng lại. Lúc này OS sẽ tự động reboot lại hệ thống.

Chúng ta sẽ đi tiếp với bản chất của các hàm cấp phát bộ nhớ. Trong OS có 2 danh sách để quản lý bộ nhớ vật lý. Danh sách 1 là những vùng nhớ vật lý đang được sử dụng. Tất cả các địa chỉ bộ nhớ vật lý trong danh sách này đều được cấp phát các địa chỉ virtual address tương ứng. Danh sách 2 là những vùng nhớ vật lý chưa được sử dụng. Tất cả địa chỉ bộ nhớ vật lý trong danh sách 2 đều không có địa chỉ virtual nào gán nào nó cả. Các hàm cấp phát bộ nhớ sẽ tìm trong danh sách 2 một đoạn bộ nhớ vật lý phù hợp rồi gán cho nó một địa chỉ virtual sau đó move nó sang danh sách 1. Nếu 1 vùng nhớ vật lý nằm ở danh sách 1 nhưng nó lại không được bất cứ ai sử dụng thì nó sẽ trở thành vùng memory leak.

Sau khi hiểu được bản chất của việc cấp phát bộ nhớ, chúng ta sẽ tiếp tục với 2 khái niệm nữa là memory leak ở user-space và memory leak ở kernel-space.

Memory leak ở user-space được gây ra bởi việc cấp phát bộ nhớ trong các process. Tuy nhiên mỗi 1 process muốn cấp phát bộ nhớ thì đều phải thông qua hệ điều hành. Do đó OS sẽ lưu lại toàn bộ thông tin về bộ nhớ mà process đó cấp phát. Khi process kết thúc, OS sẽ giải phóng toàn bộ memory mà process đó đã cấp phát thông qua những thông tin mà OS đã lưu lại. Do đó 1 process cứ việc gây memory leak thoải mái nhưng khi nó kết thúc, toàn bộ memory leak sẽ được giải phóng bởi OS.

Memory leak dưới kernel-space thì lại khác. Do toàn bộ kernel-space là 1 process và kernel-space process chỉ kết thúc khi reboot hệ thống. Do đó nếu 1 vùng memory bị leak dưới kernel-space thì nó sẽ nằm đó mãi mãi. Nó chỉ được free khi hệ thống khởi động lại.

Đến đây là tất cả những gì mình biết về memory leak. Mình rất mong nhận được sự góp ý của mọi người.

** Nếu bạn muốn viết các nội dung đặt biệt thì hãy làm theo hướng dẫn sau

Xem thêm 10 bình luận
Viết blog mới của bạn
Báo lỗi trang
Đang tải