3. 内存泄露原理:什么是内存泄露、内存泄露的成因、内存泄露的危害

好,咱们今天聊一个老生常谈但又特别容易翻车的话题——内存泄露。

说实话,我在IVI项目里踩过的坑,有一半以上都跟内存泄露有关。你想想看,车机系统跑着跑着,导航卡了、音乐断了、倒车影像延迟了……用户的第一反应就是“这车机真垃圾”。但背后,很可能就是内存泄露在作祟。

3.1 什么是内存泄露?

先给个最直白的定义:内存泄露,就是程序申请了一块内存,用完之后没还给系统。

说白了,你找系统借了100块钱,说好明天还,结果你忘了,系统也忘了。但系统记性没那么差,它一直记着这笔账。时间一长,系统手里能用的钱就越来越少。

在C/C++的世界里,我们手动用 malloc()new 申请内存,用完后必须用 free()delete 释放。如果只申请不释放,这块内存就“漏”了。

核心定义:内存泄露 = 已分配但无法再访问的内存 + 未被释放的内存。

举个例子,你写了个函数:

void leak_example() {
    int *p = (int *)malloc(100 * sizeof(int));
    // 用了一下 p,然后……
    return;  // 忘了 free(p)
}

函数执行完,指针 p 没了,但那100个整数的空间还在内存里。没人能再找到它,它就成了“孤儿内存”。

3.2 内存泄露的成因

成因其实不复杂,我归纳成三类:

3.2.1 忘记释放

这是最常见的情况。我在项目中遇到过,一个同事写了个音频解码模块,每次解码都 malloc 一个缓冲区,但只在正常路径下 free,异常分支里直接 return 了。结果呢?播一首歌漏一次,播十首歌漏十次。

// 错误示例:异常路径忘记释放
void decode_audio(const char *file) {
    char *buffer = (char *)malloc(1024);
    if (open_file(file) == NULL) {
        return;  // 这里漏了!buffer 没释放
    }
    // 正常处理...
    free(buffer);
}

3.2.2 指针覆盖

这个更隐蔽。你有一个全局指针指向一块内存,后来你给它赋了新地址,旧地址就再也找不回来了。

char *g_buffer = (char *)malloc(256);
g_buffer = (char *)malloc(512);  // 旧的256字节永远丢失了

嗯,这里要注意:每次赋值前,先想想旧地址要不要释放。

3.2.3 容器或链表未清理

在IVI系统中,我们经常用链表管理播放列表、消息队列。如果只删节点,不释放节点里的数据,那数据就漏了。

// 错误示例:只删节点,不释放数据
typedef struct Node {
    char *data;
    struct Node *next;
} Node;

void delete_node(Node *head, Node *target) {
    // 只做了链表操作,没 free(target->data)
    // target->data 指向的内存泄露了
}

我曾经排查过一个蓝牙音乐卡顿的问题,最后发现就是消息队列的节点数据没释放,每切一首歌就漏几百字节,跑了两小时后内存耗尽。

3.3 内存泄露的危害

危害有多大?我直接说结论:内存泄露是IVI系统的慢性毒药。

危害类型 具体表现 我见过的真实案例
性能下降 系统响应变慢,界面卡顿 导航地图滑动掉帧,用户投诉
OOM(内存耗尽) 进程被系统杀死,功能中断 倒车影像突然黑屏,差点出事故
系统不稳定 随机崩溃、重启 蓝牙电话通话中自动断开
累积效应 运行时间越长,问题越严重 长途驾驶3小时后,音乐播放器崩溃

警告:IVI系统是7x24小时运行的。一个每小时泄露1KB的程序,跑一个月就是720KB。如果多个模块都有泄露,系统撑不过一周。

你想想看,用户刚提车时车机很流畅,开了三个月后越来越卡。这不是硬件老化,很可能是内存泄露在慢慢“吃掉”可用内存。

我记得有一次,客户反馈说“导航用久了会闪退”。我们远程抓了日志,发现进程的RSS(物理内存占用)从启动时的80MB,一路涨到400MB,然后被Linux OOM Killer干掉了。排查下来,是地图渲染模块每刷新一次画面就申请一块纹理内存,但释放逻辑写错了条件。

避坑指南:我曾经在代码评审时反复强调一个原则——谁申请,谁释放;谁持有,谁负责。每个 malloc 都要对应一个 free,每个 new 都要对应一个 delete。别想着“后面再补”,后面大概率会忘。

最后总结一下:内存泄露的本质是资源管理失控。它不像段错误那样立刻崩溃,而是像温水煮青蛙,等你发现时,系统已经病入膏肓了。

下一节,我会讲怎么用工具把这些“漏点”一个个揪出来。到时候你就能体会到,排查内存泄露其实挺有意思的——就像破案一样。