Trong lúc quậy code C, có thể bạn đã gặp một tình huống chương trình dường như "có chút hơi men"...lờ đờ, ngà ngà say:
- Chương trình chạy ngon
- Không crash
- Không báo lỗi
Nhưng chạy một lúc thì:
- chậm dần
- lag dần
- rồi… "đứng hình"
Bạn nghĩ:
"Chắc máy yếu…", hoặc là "mạng yếu", hoặc "một cái gì đó...yếu"
Không. Rất có thể bạn vừa dính memory leak.
Memory leak là gì?
Nói đơn giản:
Memory leak xảy ra khi bạn cấp phát bộ nhớ nhưng quên giải phóng
Trong C:
int *p = malloc(sizeof(int));
Bạn đã "xin" một vùng nhớ từ hệ điều hành
Nhưng nếu bạn không:
free(p);
Vùng nhớ đó sẽ không bao giờ được trả lại
Ví dụ thực tế
Bạn đi thuê phòng khách sạn trong kỳ nghỉ Lễ. Sau đó khóa cửa phòng, quay về nhà, đi làm đi học như bình thường.
Nhưng… không bao giờ trả phòng khách sạn.
Một mình bạn chiếm 1 phòng --> không sao
1000 người như vậy --> hết phòng --> "toang"
Ví dụ code kinh điển
#include <stdlib.h>
int main() {
while (1) {
int *p = malloc(sizeof(int));
}
}Mỗi vòng lặp:
- xin thêm 1 vùng nhớ
- nhưng không trả
Kết quả:
RAM tăng dần
rồi…
Vì sao memory leak nguy hiểm?
Khác với segmentation fault:
- Segfault --> crash ngay (còn biết đường sửa)
- Memory leak --> không crash ngay. Cứ tưởng là mọi thứ ổn!
Nó âm thầm:
- ăn RAM
- làm chương trình chậm
- lâu dài → sập
Kiểu như sóng biển vỗ bờ, âm thầm xâm lấn vậy...Từ từ, từ từ...đất lở, sụt lún lúc nào không hay...
5 nguyên nhân phổ biến
1. Quên free
int *p = malloc(sizeof(int));
// quên freeĐây là "classic"
2. Ghi đè pointer
int *p = malloc(sizeof(int));
p = malloc(sizeof(int)); // leak vùng nhớ cũBạn mất luôn địa chỉ vùng nhớ đầu tiên → không free được nữa
3. Return sớm (quên dọn dẹp)
int *p = malloc(sizeof(int));
if (error) return; // leakChưa kịp free đã "bỏ chạy"
4. Cấu trúc phức tạp (struct, linked list…)
Khi dùng:
- list
- tree
Rất dễ:
- free thiếu
- free sai
5. Lặp nhiều lần (loop)
Code tưởng đúng:
while (1) {
char *buf = malloc(100);
}Nhưng:
chạy lâu --> chết chắc
Thực hành
Để hiểu rõ hơn, mục sở thị kết quả bằng xương bằng thịt, chúng ta sẽ cần thực hành một chút.
Bạn copy code sau vào: Online C Compiler
#include <stdlib.h>
#include <stdio.h>
int main() {
int count = 0;
while (1) {
malloc(1000); // leak
count++;
if (count % 10000 == 0) {
printf("Allocated %d blocks\n", count);
}
}
return 0;
}Bấm Run chạy thử
Bạn sẽ thấy:
- chương trình chạy
- nhưng RAM tăng dần
Cách phát hiện memory leak
Cách 1: Quan sát RAM
Task Manager / top / htop
thấy RAM tăng liên tục --> rất đáng nghi
Cách 2: Dùng tool chuyên dụng
Ví dụ:
Valgrind (Linux)
valgrind ./program
Nó sẽ báo:
- chỗ nào leak
- leak bao nhiêu
Cách 3: Tự discipline (Tự mò mẫm)
Rule đơn giản:
malloc ở đâu --> free ở đó (hoặc có kế hoạch rõ ràng)
Cách tránh memory leak
1. malloc --> luôn nghĩ đến free
Viết code mà không nghĩ đến free là… sớm muộn gì cũng leak
2. Set NULL sau khi free
free(p);
p = NULL;Tránh dùng lại nhầm
3. Không ghi đè pointer
Nếu cần:
free(p);
p = malloc(sizeof(int));4. Với project lớn, rất cần viết rule rõ ràng
- Ai cấp phát?
- Ai giải phóng?
Không rõ = leak
Một sự thật hơi "đau"
Rất nhiều phần mềm ngoài đời:
- không crash
- nhưng chạy lâu → chậm
Lý do: memory leak
Tổng kết
Memory leak không làm chương trình crash ngay
Nhưng nó "ăn dần" tài nguyên
Chỉ cần nhớ:
- malloc --> phải free
- Không free --> leak
- Leak nhiều --> chết
FAQ nhanh
Memory leak có gây segmentation fault không?
Không trực tiếp, nhưng có thể gián tiếp khi hết memory
Có thể tránh hoàn toàn memory leak không?
Rất khó, nhưng có thể giảm rất nhiều nếu quản lý tốt
Ngôn ngữ khác có memory leak không?
Có, nhưng ít hơn (do có garbage collector)
Bạn có thể cũng đang gặp:
Segmentation fault trong C là gì?
Con trỏ NULL nguy hiểm ra sao?
Stack vs Heap khác nhau thế nào?
Segmentation fault trong C là gì?
Con trỏ NULL nguy hiểm ra sao?
Stack vs Heap khác nhau thế nào?