动态分配的内存用完不还,就叫内存泄漏。单次看没什么,长期跑的程序(服务器、后台任务)里,泄漏的内存越积越多,最后把系统内存吃光、程序崩溃。下面讲泄漏怎么发生、怎么避免、有什么后果。

内存怎么分两块

程序的内存大致分两块:栈和堆。

  • :局部变量、函数参数,函数一返回自动回收,不用操心。
  • malloc() / calloc() 动态分配的地盘,不会自动回收,必须手动 free()。

内存泄漏就是堆上分配了却一直不 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 是一对,配平才健康,写动态分配的代码时,先在脑子里过一遍这块内存最后由谁负责归还。