动态分配的内存用完不还,就叫内存泄漏。单次看没什么,长期跑的程序(服务器、后台任务)里,泄漏的内存越积越多,最后把系统内存吃光、程序崩溃。下面讲泄漏怎么发生、怎么避免、有什么后果。
内存怎么分两块
程序的内存大致分两块:栈和堆。
内存泄漏就是堆上分配了却一直不 free。
一个典型的泄漏例子
#include <stdio.h>
#include <stdlib.h>
int main() {
/* 动态分配 5 个 int 的空间 */
int *ptr = (int *)malloc(5 * sizeof(int));
if (ptr == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
/* 用这块内存 */
ptr[0] = 10;
ptr[1] = 20;
printf("Values: %d %d\n", ptr[0], ptr[1]);
/* free(ptr); ← 忘了释放,内存泄漏! */
return 0;
}程序能正常跑出:
Values: 10 20但 malloc 出来的空间从没还给系统,程序结束前一直占着,这就是泄漏。单个程序退出后系统会回收,问题出在长期运行中反复发生。
泄漏的常见原因
- 忘了 free():malloc/calloc 之后没有对应的 free。
- 指针被覆盖/丢失:还没 free 就把指针指向别处,或者指针出了作用域,原来那块内存再也够不着,无法释放。
- 循环里累积:循环内不断分配又忘了释放,每次循环漏一点,越漏越多。
/* 循环里分配,却只在循环外释放一次 */
for (int i = 0; i < 1000; i++) {
char *buf = (char *)malloc(1024);
/* 用 buf ... */
/* 忘了 free(buf) ,1000 次循环漏掉 1MB */
}避免泄漏的做法
- 每次分配都配一个释放:写完 malloc 就想想对应的 free 在哪。
- 释放前别弄丢指针:需要换指针时,先 free 旧的。
- 函数里统一出口:用 goto 收尾清理(见错误处理相关文章),或设计成谁分配谁释放。
- 借助工具:Linux 下 Valgrind 能直接告诉你哪一行泄漏了多少字节,排查很方便。
泄漏的后果
- 慢慢吃掉系统可用内存,其他进程也跟着受影响。
- 程序越来越慢、响应越来越迟钝。
- 内存耗尽时报 Out of Memory,程序崩溃。
- 服务器这类常驻进程最惨,泄漏累积到一定程度直接罢工。
malloc 和 free 是一对,配平才健康,写动态分配的代码时,先在脑子里过一遍这块内存最后由谁负责归还。