3、内存瓶颈根源分析:SRAM、DRAM、Flash的层级结构与访问延迟

做边缘AI的朋友,十有八九都被内存卡过脖子。模型跑不起来,不是算力不够,是数据搬不动。我刚开始做嵌入式AI那会儿,总觉得CPU频率够高就行,结果被内存延迟狠狠上了一课。

今天咱们就掰开揉碎,看看SRAM、DRAM、Flash这三兄弟到底怎么分工,又为什么成了瓶颈。

3.1 为什么要有内存层级?

你想想看,如果只用一种存储器件,会怎样?

用SRAM吧,快是真快,但贵得离谱,1MB就要几十块钱。用DRAM吧,容量上去了,但速度掉下来。用Flash吧,断电不丢数据,可写入慢得像蜗牛。

所以芯片设计者搞了个折中方案——内存层级结构。说白了,就是把快的做小放近处,把慢的做大放远处。

核心原则:越靠近CPU的存储器,速度越快、容量越小、成本越高。

我在项目中遇到过这样一个场景:一个目标检测模型,推理一次要300ms,其中200ms都花在从DDR搬数据上。你说气不气人?

3.2 SRAM:速度之王,容量之殇

SRAM,静态随机存取存储器。名字里带“静态”,是因为它不需要像DRAM那样不断刷新。

结构特点:

  • 每个存储单元由6个晶体管组成
  • 数据以锁存器形式保存
  • 访问速度:1~5ns

为什么快?因为它是全硬件逻辑,没有复杂的刷新周期。CPU的L1、L2缓存,用的就是SRAM。

但问题也很明显:

  • 6个晶体管存1bit,面积大
  • 片上SRAM通常只有几百KB到几MB
  • 成本高,不适合做大容量存储

我的经验:在STM32这类MCU上做AI,SRAM就是命根子。我习惯把模型权重放在Flash,把中间特征图放在SRAM。如果SRAM不够,就得做tiling——把大图切成小块处理。

3.3 DRAM:容量担当,延迟刺客

DRAM,动态随机存取存储器。为什么叫“动态”?因为它需要不断刷新,否则电容里的电荷会漏掉。

结构特点:

  • 每个存储单元只有1个晶体管+1个电容
  • 数据以电荷形式保存
  • 访问速度:50~100ns

你看,比SRAM慢了10~20倍。但容量可以做到GB级别,价格也便宜得多。

DRAM的三大痛点:

  1. 刷新开销:每64ms要刷新一次,占用带宽
  2. 行冲突:连续访问不同行时,需要预充电,延迟暴增
  3. 带宽瓶颈:DDR接口虽然快,但协议开销大

避坑指南:我曾经在RK3588上跑YOLOv5,发现推理时间忽高忽低。查了半天,原来是DDR的自动刷新和推理任务撞车了。后来我把刷新周期调成了手动模式,在推理间隙刷新,问题才解决。

3.4 Flash:断电不丢,写入要命

Flash存储器,咱们常用的NAND Flash和NOR Flash。边缘设备上,它主要存模型参数和固件。

关键参数:

类型 读延迟 写延迟 擦除延迟 寿命
NOR Flash ~80ns ~1μs ~1s 10万次
NAND Flash ~25μs ~200μs ~2ms 1万次

看到没?读还行,写和擦除慢得离谱。而且Flash有写入次数限制,不能频繁修改。

在AI场景下的应用:

  • 模型参数通常烧录在Flash里
  • 推理时,参数从Flash读到DRAM或SRAM
  • OTA升级时,要小心擦写次数

我建议:如果模型不大(比如<1MB),可以直接在Flash里执行代码,这叫XIP(eXecute In Place)。省掉加载到RAM的时间,延迟能降不少。

3.5 访问延迟对比:数字会说话

咱们用具体数字感受一下差距。假设CPU主频1GHz,一个时钟周期1ns:

存储层级 典型延迟 CPU周期数 比喻
L1 Cache (SRAM) 1~2ns 1~2 从桌上拿笔
L2 Cache (SRAM) 5~10ns 5~10 从书架拿书
DDR4 DRAM 50~100ns 50~100 下楼取快递
NAND Flash 25~100μs 25000~100000 开车去图书馆

嗯,这里要注意:Flash的延迟是SRAM的几万倍。所以做AI推理时,尽量别让CPU直接访问Flash。

3.6 实战:如何绕过内存瓶颈

说了这么多理论,来点实际的。我在做边缘AI项目时,总结了几条经验:

1. 数据本地化

尽量让数据待在离计算单元近的地方。比如用NPU时,把权重提前加载到NPU的本地SRAM里。

// 伪代码示例:提前加载权重到SRAM
void load_weights_to_sram() {
    for (int i = 0; i < NUM_LAYERS; i++) {
        // 从Flash读到DRAM
        memcpy(dram_buffer, flash_addr[i], layer_size[i]);
        // 再从DRAM搬到NPU SRAM
        npu_load_weights(dram_buffer, sram_addr[i], layer_size[i]);
    }
}

2. 流水线预取

别等CPU要数据了才去取。提前把下一批数据准备好,隐藏延迟。

3. 内存对齐

DRAM访问有burst模式,一次读8个字节比读1个字节快不了多少。所以数据结构要按16字节对齐。

我曾经踩过的坑:在某个项目里,我用malloc分配缓冲区,结果地址没对齐。DMA传输时,每次都要做字节对齐处理,性能直接腰斩。后来改用aligned_alloc,问题解决。

4. 避免频繁上下文切换

每次任务切换,缓存都会被污染。在实时AI系统中,我习惯把推理任务绑在特定核上,减少切换。

3.7 小结

内存瓶颈,说白了就是速度、容量、成本三者不可兼得。SRAM快但小,DRAM大但慢,Flash持久但更慢。

做边缘AI,你得学会在三个层级间跳舞。把最常用的数据放SRAM,中等常用的放DRAM,不常用的放Flash。再配合预取、对齐、流水线这些技巧,才能把硬件性能榨干。

下一章,咱们聊聊模型量化——怎么把32位浮点模型压成8位甚至4位,让内存占用直接砍半。到时候你会发现,原来瓶颈是可以“绕”过去的。