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系统里,这几样东西是这样配合的:

  1. 启动时:CPU从Flash里把程序代码和模型权重读到DRAM。
  2. 运行时:CPU从DRAM里取指令和数据,Cache自动缓存热点数据。
  3. 推理时:DMA把输入数据从外设搬到DRAM,再把DRAM里的数据搬到NPU或DSP的本地SRAM。
  4. 输出时:DMA把推理结果从SRAM搬到DRAM,再搬到显示或通信外设。

整个过程,CPU、Cache、DMA各司其职,谁也别闲着,谁也别抢活。这就是高性能边缘AI系统的内存管理精髓。

核心观点:内存管理的本质,就是让「对的数据在对的时刻出现在对的位置」。SRAM、DRAM、Flash、Cache、DMA,都是实现这个目标的工具。工具没有好坏,只有会不会用。

好了,这一章就到这里。下一章咱们聊聊「内存分配策略:静态分配 vs 动态分配」,这可是嵌入式AI开发里最容易踩坑的地方。到时候我会分享几个我当年被坑惨了的案例,保证让你印象深刻。