3、内存基础:SRAM、DRAM、Flash的区别,Cache的工作原理,DMA的作用
做嵌入式AI的朋友,内存这块儿是绕不开的坎儿。我见过不少新手,算法模型跑得挺溜,一上板子就崩,十有八九是内存没搞明白。今天咱们就把SRAM、DRAM、Flash、Cache和DMA这几个老伙计,好好捋一捋。
3.1 SRAM、DRAM、Flash:三兄弟各司其职
这三兄弟,说白了就是速度、容量、成本之间的博弈。你想想看,没有一种存储技术能同时做到又快又大又便宜,这不现实。
SRAM(静态随机存取存储器)
SRAM是速度之王。它用触发器(Flip-Flop)存数据,只要不断电,数据就不丢。我习惯把它比作「桌面上的笔记本」——随手就能写,随时都能看,但桌面就这么大,放不了几本。
- 优点:极快,纳秒级访问。CPU内部的一级、二级缓存,基本都是SRAM。
- 缺点:贵,占面积大。一个SRAM单元要6个晶体管,集成度上不去。
- 我在项目中遇到过:有一次做图像预处理,想把整帧数据放SRAM里加速,结果发现芯片SRAM只有512KB,根本塞不下。最后只能分块处理,这就是现实。
DRAM(动态随机存取存储器)
DRAM是容量担当。它靠电容存数据,电容会漏电,所以得不停地「刷新」。说白了,就像个漏水的桶,你得一直往里倒水才能保持水位。
- 优点:容量大,成本低。一个DRAM单元只要1个晶体管+1个电容。
- 缺点:慢(相对SRAM),需要刷新。访问延迟在几十纳秒级别。
- 避坑指南:我曾经在DDR3上做实时推理,没注意刷新周期对延迟的影响,结果偶尔出现帧率抖动。后来把关键数据放SRAM里,才稳住。
Flash(闪存)
Flash是持久化存储。断电不丢数据,但写入速度慢,而且有擦写寿命限制。我习惯叫它「硬盘的嵌入式版本」。
- 优点:非易失性,容量大,便宜。
- 缺点:写入慢(毫秒级),有擦写次数限制(一般10万次左右)。
- 注意:在边缘AI设备上,模型权重通常存在Flash里,启动时加载到DRAM或SRAM中运行。千万别在Flash里频繁写日志,否则芯片先「退休」了。
一句话总结:SRAM是跑车,DRAM是卡车,Flash是仓库。跑车拉货少但快,仓库装得多但慢。你得根据场景选对车。
3.2 Cache的工作原理:为什么它能「骗」过CPU?
Cache,说白了就是CPU和主存之间的「缓冲带」。CPU跑得太快,DRAM跟不上,怎么办?把最近常用的数据先搬到SRAM里,这就是Cache。
局部性原理
Cache能工作,靠的是两个局部性:
- 时间局部性:刚用过的数据,很可能马上再用。比如循环里的变量。
- 空间局部性:刚用过的数据附近的数据,很可能马上要用。比如数组的连续访问。
你想想看,程序执行时,90%的时间都在访问10%的数据。Cache就是抓住了这个规律。
Cache的层级结构
现代处理器一般有L1、L2、L3三级Cache。L1最快但最小(几十KB),L3最大但稍慢(几MB)。我习惯把L1叫「贴身秘书」,L2叫「部门经理」,L3叫「公司档案室」。
| 层级 | 典型大小 | 访问延迟 | 位置 |
|---|---|---|---|
| L1 Cache | 32KB - 128KB | ~1ns | CPU核心内部 |
| L2 Cache | 256KB - 1MB | ~5ns | CPU核心内部 |
| L3 Cache | 2MB - 32MB | ~15ns | 多核共享 |
| DRAM | 几GB | ~50ns | 片外 |
Cache Miss的代价
Cache没命中,就得去DRAM里取数据,这时间够CPU干几百条指令了。我在做AI推理优化时,最怕的就是Cache Miss。有一次优化卷积算子,把数据排布从NHWC改成NCHW,Cache命中率从60%提到95%,推理速度直接翻倍。
我的小技巧:写代码时尽量让数据访问是连续的。比如遍历二维数组,按行遍历比按列遍历快得多,因为按行访问能充分利用Cache的空间局部性。
3.3 DMA的作用:让CPU喘口气
DMA(直接存储器访问),说白了就是个「数据搬运工」。没有DMA的时候,CPU得亲自把数据从外设搬到内存,或者从内存搬到外设。CPU多忙啊,又要算指令,又要搬数据,累都累死了。
DMA怎么工作?
DMA控制器是个独立硬件。CPU只需要告诉它:「从地址A搬N个字节到地址B」,然后就可以去干别的事了。DMA搬完数据后,发个中断通知CPU:「活干完了,你来处理吧」。
// 伪代码:DMA传输配置示例
void dma_transfer(uint32_t *src, uint32_t *dst, uint32_t size) {
// 1. 配置DMA源地址
DMA->SRC_ADDR = (uint32_t)src;
// 2. 配置DMA目标地址
DMA->DST_ADDR = (uint32_t)dst;
// 3. 配置传输大小
DMA->TRANS_SIZE = size;
// 4. 启动DMA传输
DMA->CTRL |= DMA_START;
// CPU可以去做其他事情了
// 5. 等待DMA完成中断
while(!(DMA->STATUS & DMA_DONE));
}
在边缘AI中的应用
DMA在边缘AI里太重要了。我举个例子:摄像头采集一帧图像,如果让CPU逐像素搬运,CPU基本就废了。用DMA的话,CPU只需要启动一次传输,然后就可以去准备下一帧的推理计算。
- 图像采集:DMA把摄像头数据直接搬到DRAM,CPU零参与。
- 模型加载:DMA把Flash里的模型权重搬到SRAM,CPU同时做初始化。
- 数据输出:DMA把推理结果搬到显示缓冲区,CPU继续下一轮推理。
注意:DMA虽然好,但也不是万能的。传输小数据时(比如几十个字节),DMA的配置开销可能比CPU直接搬还大。我一般建议,传输量超过几百字节才用DMA,否则就老老实实让CPU搬。
3.4 三者如何协同工作?
嗯,到这里你应该明白了。一个典型的边缘AI系统里,这几样东西是这样配合的:
- 启动时:CPU从Flash里把程序代码和模型权重读到DRAM。
- 运行时:CPU从DRAM里取指令和数据,Cache自动缓存热点数据。
- 推理时:DMA把输入数据从外设搬到DRAM,再把DRAM里的数据搬到NPU或DSP的本地SRAM。
- 输出时:DMA把推理结果从SRAM搬到DRAM,再搬到显示或通信外设。
整个过程,CPU、Cache、DMA各司其职,谁也别闲着,谁也别抢活。这就是高性能边缘AI系统的内存管理精髓。
核心观点:内存管理的本质,就是让「对的数据在对的时刻出现在对的位置」。SRAM、DRAM、Flash、Cache、DMA,都是实现这个目标的工具。工具没有好坏,只有会不会用。
好了,这一章就到这里。下一章咱们聊聊「内存分配策略:静态分配 vs 动态分配」,这可是嵌入式AI开发里最容易踩坑的地方。到时候我会分享几个我当年被坑惨了的案例,保证让你印象深刻。