做系统、驱动、存储、网络甚至嵌入式开发时,你大概率都会碰到一个词:DMA。
很多人第一次听到 DMA,脑子里会自动翻译成一句话:
“数据传输时,不用 CPU 自己搬了。”
这句话不能说错,但如果只停在这一步,理解其实还远远不够。
因为 DMA 真正厉害的地方,不只是“省 CPU”,而是它改变了整个系统里数据搬运的方式:
- CPU 不再一字节一字节地搬
- 外设可以直接和内存打交道
- 大量 I/O 场景的吞吐量和效率因此提升
这篇文章,就来把 DMA 讲清楚:
- DMA 到底是什么
- 它为什么比 CPU 亲自搬运更高效
- 它在底层到底是怎么工作的
- 它常用在哪里
- 它和中断、缓存、零拷贝是什么关系
一、DMA 到底是什么
DMA,全称是 Direct Memory Access,中文通常叫 直接内存访问。
它的核心含义只有一句话:
让外设或 DMA 控制器,直接在内存和设备之间搬运数据,而不是让 CPU 亲自逐个读写。
注意这个“直接”,不是说 CPU 完全不知道这件事。
而是说:
- CPU 不负责一条一条、一字一字地搬数据
- CPU 只负责“安排任务”
- 真正的数据搬运,由 DMA 硬件完成
所以 DMA 的本质更像是:
CPU 负责下指令,DMA 负责干体力活。
二、如果没有 DMA,会发生什么
假设网卡收到一批数据,要放进内存。
如果没有 DMA,通常只能这么干:
- 外设准备好数据
- CPU 收到通知
- CPU 从设备寄存器里读一小段数据
- CPU 再把这段数据写到内存
- 重复很多次,直到搬完
这就是典型的 PIO,也就是 Programmed I/O。
你会发现,这种方式有几个问题:
- CPU 被迫参与每一次搬运
- 数据量一大,CPU 时间大量浪费在“搬箱子”上
- CPU 本来可以做计算、调度、业务逻辑,现在却在干重复体力活
如果是磁盘、网卡、声卡、摄像头这类高频 I/O 设备,PIO 很快就会成为瓶颈。
三、DMA 为什么更高效
有了 DMA 之后,流程会变成这样:
- CPU 告诉 DMA:“把设备的数据搬到这块内存”
- DMA 自己去和设备、内存打交道
- 数据搬完后,DMA 再通知 CPU:“好了”
也就是说,CPU 只参与:
真正的大批量数据传输,不再占着 CPU 一直干。
这带来的好处很直接:
1. 降低 CPU 开销
CPU 不用重复执行大量 I/O 搬运指令。
2. 提高并行度
CPU 可以继续算别的,DMA 在旁边搬数据。
3. 提升吞吐量
对磁盘、网络、音视频采集这类大流量场景尤其明显。
所以很多人说 DMA 的价值是“解放 CPU”,这话没错。
但更准确地说,是:
把数据搬运这件事,从通用处理器手里,交给了更适合干这件事的硬件。
四、DMA 的底层工作机制,到底是什么
DMA 的工作机制,通常可以概括成 4 步。
1. CPU 先配置 DMA
CPU 会先告诉 DMA 几个关键参数:
- 源地址在哪里
- 目标地址在哪里
- 要搬多少数据
- 传输方向是什么
- 什么时候算完成
- 是否需要中断通知
比如:
- 磁盘数据搬到内存
- 内存数据发给网卡
- ADC 采样结果写入内存缓冲区
这些都属于 DMA 可以接手的任务。
2. DMA 获得总线使用权
DMA 要搬数据,就得访问内存。
访问内存通常要经过系统总线或片上互连。
所以 DMA 在真正传输前,需要获得总线访问权。
这一步你可以理解成:
DMA 需要向系统申请“我现在要上路运货”。
拿到权限后,它就可以在设备和内存之间传输数据。
3. DMA 开始搬运数据
一旦开始工作,DMA 会按照配置:
- 从设备读数据写入内存
- 或者从内存读数据写入设备
- 或者在某些系统里做内存到内存搬运
整个过程中,数据不需要先进入 CPU 寄存器再写回内存。
这就是“数据不经过 CPU 亲自搬运”的真正含义。
注意,这里不是说数据“绕过了 CPU 所在的物理芯片”,而是说:
CPU 不参与逐条 load/store 指令式的搬运。
4. DMA 完成后通知 CPU
传输结束后,DMA 通常会通过中断告诉 CPU:
- 这次搬运完成了
- 可以处理下一批数据了
- 或者缓冲区已经写满/读空了
于是 CPU 再来做后续逻辑,比如:
- 唤醒线程
- 交给协议栈
- 更新缓冲区指针
- 发起下一次 DMA
所以 DMA 并不是“CPU 完全不管”,而是:
CPU 管流程,DMA 管搬运。
五、一个最好理解的例子:网卡收包
拿网卡举例最容易理解。
假设网卡收到网络数据包,目标是把它交给操作系统处理。
如果没有 DMA:
- 网卡收到数据
- CPU 不断从网卡寄存器读取
- CPU 再把数据写到内存
- CPU 再通知 内核协议栈 继续处理
如果有 DMA:
- 操作系统提前在内存里准备好接收缓冲区
- CPU 把这块缓冲区地址告诉网卡或 DMA 引擎
- 网卡收到包后,直接通过 DMA 写入内存缓冲区
- 写完后触发中断
- CPU 再来处理这个包
你会发现,CPU 的角色从“搬运工”变成了“调度员”。
这也是现代高性能网络、存储系统离不开 DMA 的原因。
六、DMA 常用在哪里
DMA 几乎存在于所有高吞吐 I/O 场景里。
1. 磁盘和存储
磁盘读写的数据量大,如果让 CPU 每次亲自搬,成本太高。
所以 SSD、SATA、NVMe 等设备都会大量依赖 DMA。
2. 网卡
网络包收发频繁,而且速度越来越高。
没有 DMA,高速网络基本跑不起来。
3. 音视频设备
比如:
这些都需要持续、稳定地搬运大量数据,非常适合 DMA。
4. 嵌入式外设
在 MCU 或 SoC 中,DMA 也非常常见,很多实时系统里,DMA 是降低 CPU 占用的关键手段。
5. GPU 和加速器
GPU、AI 加速卡、FPGA 这类设备,本质上都需要高效搬运大量数据。
DMA 是它们和主存之间高速交互的基础能力之一。
七、DMA 和中断是什么关系
很多人会把 DMA 和中断混在一起,其实它们不是一回事。
- DMA 解决的是:谁来搬数据
- 中断 解决的是:什么时候通知 CPU
DMA 负责搬,中断负责告诉 CPU:
两者经常配合使用,所以容易一起出现。
但本质上,它们是两个不同机制。
可以这样理解:
八、DMA 是不是完全不占 CPU?
不是。这是最常见的误解之一。
DMA 只是减少 CPU 对“数据搬运过程”的直接参与,CPU 仍然需要做很多工作:
- 配置 DMA 描述符或寄存器
- 分配和管理缓冲区
- 处理中断
- 做协议、文件系统、业务逻辑处理
- 处理异常和重传
所以正确说法不是:“DMA 完全不用 CPU。”
而是:“DMA 不让 CPU 亲自做重复的数据搬运动作。”
这两个说法差别很大。
九、DMA 和“零拷贝”是一回事吗?
也不是。DMA 和零拷贝经常一起出现,但不是同一个概念。
DMA 强调的是:
零拷贝 强调的是:
举个例子:
- 网卡通过 DMA 把数据放到内核缓冲区
- 内核再复制到用户缓冲区
这里用了 DMA,但仍然发生了拷贝。
所以这不算真正意义上的零拷贝。
反过来,零拷贝方案里常常会依赖 DMA,但零拷贝关注的是拷贝次数,DMA 关注的是搬运方式。
DMA 不等于零拷贝,但零拷贝常常离不开 DMA。
十、DMA 为什么会牵扯到缓存一致性
这部分稍微底层一点,但非常重要。
CPU 访问内存时,常常会经过缓存。
而 DMA 访问内存时,可能是直接绕过 CPU cache 的。
这就带来一个问题:
- CPU 看到的数据,可能在 cache 里
- DMA 看到的数据,可能在内存里
- 两边未必总是同步
这就叫 缓存一致性 问题。
例如:
- CPU 改了缓冲区内容,但还没刷回内存,DMA 读到的是旧数据
- DMA 刚把新数据写到内存,CPU 却还在读 cache 里的旧副本
所以做 DMA 时,系统通常要处理:
- cache flush
- cache invalidate
- 一致性内存映射
- IOMMU 或平台相关同步操作
这也是为什么驱动开发里,DMA 往往比表面上看起来复杂得多。
十一、DMA 还有哪些常见形态
DMA 并不是只有一种固定玩法。
常见还有这些形式:
1. 单次传输
搬一段固定大小的数据,搬完结束。
2. 循环 DMA
常用于音频、采样、串口持续接收,搬到缓冲区尾部后再回到开头,持续工作。
3. Scatter-Gather DMA
不用要求数据必须放在一整块连续物理内存里。
DMA 可以根据描述符链表,依次搬多个分散内存块。
这在高性能网络和存储里非常常见。
4. Memory-to-Memory DMA
不只是设备和内存之间。
有些 DMA 控制器还支持内存到内存搬运,用来做高速 copy。
十二、什么时候特别适合用 DMA
一般来说,下面这些场景非常适合 DMA:
- 数据量大
- 传输频繁
- 对吞吐量要求高
- CPU 资源紧张
- 外设本身支持 DMA
- 实时性要求较高,不希望 CPU 被搬运拖住
典型例子包括:
- 高速网卡收发
- 磁盘大块读写
- 视频流采集
- 音频连续播放
- MCU 的串口大批量传输
- 高速 ADC 采样入缓冲区
十三、什么时候 DMA 反而不划算
DMA 也不是任何时候都值得上。
如果数据量很小、传输很少,DMA 的配置成本和中断处理成本,可能反而不划算。
比如只传几个字节:
这时候直接由 CPU 搬,可能更简单,也更快。
所以 DMA 更适合:大块、连续、高频的数据传输。
而不是所有 I/O 都无脑 DMA。
十四、总结
DMA,也就是直接内存访问,本质上是一种让硬件代替 CPU 搬数据的机制。
它的关键点有 5 个:
- CPU 负责配置和发起任务
- DMA 负责在设备和内存之间实际搬运数据
- 数据不需要经过 CPU 寄存器逐个转手
- 传输结束后通常通过中断通知 CPU
- 它大幅降低 CPU 在 I/O 搬运上的消耗
所以你可以把 DMA 记成一句话:
CPU 不再亲自搬数据,而是把搬运工作交给专门的硬件去做。
这也是现代操作系统、驱动、网络、存储和嵌入式系统中,一个非常基础、又非常关键的底层能力。
对这类底层技术感兴趣?欢迎来 云栈社区 一起深入探讨。