1. 内存泄漏基础
各位同学好,我是老张。在嵌入式领域摸爬滚打了十几年,今天咱们来聊聊MTK8676平台上一个让人头疼的问题——内存泄漏。说实话,我见过太多项目因为这个看似不起眼的问题,最后搞得焦头烂额。
1.1 什么是内存泄漏
内存泄漏,说白了就是程序向系统申请了一块内存,用完之后忘了还回去。你想想看,就像你借了图书馆的书,看完不还,时间长了图书馆的书架就空了,别人想借也借不到。
在C/C++开发中,我们经常用malloc、new来申请内存。但问题是,很多人只记得申请,不记得释放。我见过最夸张的一个案例,有个同事写了个循环,每次循环都new一个对象,但从来没delete过。跑了一个晚上,系统直接挂了。
典型的内存泄漏场景:
- 动态分配的内存没有释放
- 容器类对象(如std::vector)不断增长
- 回调函数中分配的内存忘记释放
- 异常处理路径中遗漏了释放操作
来看个简单的例子:
// 典型的内存泄漏代码
void process_data() {
char* buffer = (char*)malloc(1024);
// 处理数据...
// 忘记调用 free(buffer);
return; // buffer 泄漏了!
}
嗯,这里要注意。很多人觉得就1024字节,泄漏就泄漏了。但在嵌入式系统里,内存总共就那么点,积少成多,迟早出事。
1.2 内存泄漏的危害
内存泄漏的危害,我总结为三个字:慢、卡、死。
| 危害等级 | 表现 | 实际影响 |
|---|---|---|
| 轻度 | 系统响应变慢 | 应用启动时间增加,界面卡顿 |
| 中度 | 功能异常 | 音视频不同步,导航卡死 |
| 重度 | 系统崩溃 | 黑屏重启,数据丢失 |
我在项目中遇到过最惨的一次,是车载导航系统在连续运行72小时后突然死机。查了三天,最后发现是一个地图渲染模块每次刷新都泄漏了4KB内存。72小时下来,内存被吃光了。
避坑指南:我曾经以为内存泄漏只影响长时间运行的系统。直到有一次,一个短时间运行的功能测试,因为频繁调用泄漏代码,5分钟内就把内存耗尽了。所以,别小看任何一次泄漏。
为什么会这样?因为嵌入式系统的内存资源是有限的。MTK8676平台虽然性能不错,但它的内存分配策略和PC完全不同。你想想看,PC上泄漏个几百MB可能还能撑一会儿,但在车机上,几十MB的泄漏就足以让系统崩溃。
1.3 MTK8676平台内存架构概览
MTK8676是联发科面向智能座舱的高性能芯片。它的内存架构,我个人觉得设计得挺有意思。
先看整体架构:
MTK8676 内存架构简图
┌─────────────────────────────────────┐
│ CPU Cluster │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ A78 │ │ A78 │ │ A55 │ │
│ └──────┘ └──────┘ └──────┘ │
├─────────────────────────────────────┤
│ Memory Controller │
├─────────────────────────────────────┤
│ ┌──────────┐ ┌──────────────────┐ │
│ │ DDR │ │ Internal SRAM │ │
│ │ (4-8GB) │ │ (几MB级别) │ │
│ └──────────┘ └──────────────────┘ │
└─────────────────────────────────────┘
这个平台有几个关键特点:
- DDR内存:主内存,4-8GB,用于运行应用和系统服务
- 内部SRAM:极少量,用于实时性要求高的场景
- 共享内存:用于多核通信和多媒体处理
个人经验:我建议你在做内存泄漏检测时,重点关注DDR区域。因为大部分应用代码都跑在这里,泄漏也主要发生在这里。内部SRAM虽然小,但通常由底层驱动管理,出问题的概率低很多。
MTK8676的内存管理还有个特点——它用了CMA(Contiguous Memory Allocator)机制。说白了,就是给多媒体模块预留了一大块连续内存。这块内存如果泄漏了,后果更严重,因为其他模块想用也用不了。
我记得有一次排查一个视频播放卡顿的问题,查来查去发现是CMA区域被某个驱动泄漏了30%的空间。视频解码器申请不到连续内存,只能降级处理,画面自然就卡了。
所以,在MTK8676上做内存泄漏检测,不能只看总量。你得知道内存分了几块,每块是干什么用的,泄漏发生在哪一块。这样才能精准定位问题。
好了,这一章的基础知识就讲到这里。下一章我们开始实战,我会带大家用工具在MTK8676上实际检测内存泄漏。到时候你们会发现,理论是一回事,动手又是另一回事。