找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5132

积分

0

好友

698

主题
发表于 昨天 20:21 | 查看: 6| 回复: 0

做系统、驱动、存储、网络甚至嵌入式开发时,你大概率都会碰到一个词:DMA。

很多人第一次听到 DMA,脑子里会自动翻译成一句话:

“数据传输时,不用 CPU 自己搬了。”

这句话不能说错,但如果只停在这一步,理解其实还远远不够。

因为 DMA 真正厉害的地方,不只是“省 CPU”,而是它改变了整个系统里数据搬运的方式:

  • CPU 不再一字节一字节地搬
  • 外设可以直接和内存打交道
  • 大量 I/O 场景的吞吐量和效率因此提升

这篇文章,就来把 DMA 讲清楚:

  1. DMA 到底是什么
  2. 它为什么比 CPU 亲自搬运更高效
  3. 它在底层到底是怎么工作的
  4. 它常用在哪里
  5. 它和中断、缓存、零拷贝是什么关系

一、DMA 到底是什么

DMA,全称是 Direct Memory Access,中文通常叫 直接内存访问

它的核心含义只有一句话:

让外设或 DMA 控制器,直接在内存和设备之间搬运数据,而不是让 CPU 亲自逐个读写。

注意这个“直接”,不是说 CPU 完全不知道这件事。
而是说:

  • CPU 不负责一条一条、一字一字地搬数据
  • CPU 只负责“安排任务”
  • 真正的数据搬运,由 DMA 硬件完成

所以 DMA 的本质更像是:

CPU 负责下指令,DMA 负责干体力活。

二、如果没有 DMA,会发生什么

假设网卡收到一批数据,要放进内存。
如果没有 DMA,通常只能这么干:

  1. 外设准备好数据
  2. CPU 收到通知
  3. CPU 从设备寄存器里读一小段数据
  4. CPU 再把这段数据写到内存
  5. 重复很多次,直到搬完

这就是典型的 PIO,也就是 Programmed I/O。

你会发现,这种方式有几个问题:

  1. CPU 被迫参与每一次搬运
  2. 数据量一大,CPU 时间大量浪费在“搬箱子”上
  3. CPU 本来可以做计算、调度、业务逻辑,现在却在干重复体力活

如果是磁盘、网卡、声卡、摄像头这类高频 I/O 设备,PIO 很快就会成为瓶颈。

三、DMA 为什么更高效

有了 DMA 之后,流程会变成这样:

  1. CPU 告诉 DMA:“把设备的数据搬到这块内存”
  2. DMA 自己去和设备、内存打交道
  3. 数据搬完后,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:

  1. 网卡收到数据
  2. CPU 不断从网卡寄存器读取
  3. CPU 再把数据写到内存
  4. CPU 再通知 内核协议栈 继续处理

如果有 DMA:

  1. 操作系统提前在内存里准备好接收缓冲区
  2. CPU 把这块缓冲区地址告诉网卡或 DMA 引擎
  3. 网卡收到包后,直接通过 DMA 写入内存缓冲区
  4. 写完后触发中断
  5. 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 是搬运工
  • 中断是电话通知

八、DMA 是不是完全不占 CPU?

不是。这是最常见的误解之一。

DMA 只是减少 CPU 对“数据搬运过程”的直接参与,CPU 仍然需要做很多工作:

  1. 配置 DMA 描述符或寄存器
  2. 分配和管理缓冲区
  3. 处理中断
  4. 做协议、文件系统、业务逻辑处理
  5. 处理异常和重传

所以正确说法不是:“DMA 完全不用 CPU。”

而是:“DMA 不让 CPU 亲自做重复的数据搬运动作。”

这两个说法差别很大。

九、DMA 和“零拷贝”是一回事吗?

也不是。DMA 和零拷贝经常一起出现,但不是同一个概念。

DMA 强调的是:

  • 搬运由硬件完成
  • CPU 不亲自逐字节搬

零拷贝 强调的是:

  • 减少数据在不同缓冲区之间的额外复制次数

举个例子:

  • 网卡通过 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:

  1. 数据量大
  2. 传输频繁
  3. 对吞吐量要求高
  4. CPU 资源紧张
  5. 外设本身支持 DMA
  6. 实时性要求较高,不希望 CPU 被搬运拖住

典型例子包括:

  • 高速网卡收发
  • 磁盘大块读写
  • 视频流采集
  • 音频连续播放
  • MCU 的串口大批量传输
  • 高速 ADC 采样入缓冲区

十三、什么时候 DMA 反而不划算

DMA 也不是任何时候都值得上。

如果数据量很小、传输很少,DMA 的配置成本和中断处理成本,可能反而不划算。

比如只传几个字节:

  • 还要配置 DMA
  • 还要准备描述符
  • 还要处理中断

这时候直接由 CPU 搬,可能更简单,也更快。

所以 DMA 更适合:大块、连续、高频的数据传输。

而不是所有 I/O 都无脑 DMA。

十四、总结

DMA,也就是直接内存访问,本质上是一种让硬件代替 CPU 搬数据的机制。

它的关键点有 5 个:

  1. CPU 负责配置和发起任务
  2. DMA 负责在设备和内存之间实际搬运数据
  3. 数据不需要经过 CPU 寄存器逐个转手
  4. 传输结束后通常通过中断通知 CPU
  5. 它大幅降低 CPU 在 I/O 搬运上的消耗

所以你可以把 DMA 记成一句话:

CPU 不再亲自搬数据,而是把搬运工作交给专门的硬件去做。

这也是现代操作系统、驱动、网络、存储和嵌入式系统中,一个非常基础、又非常关键的底层能力。

对这类底层技术感兴趣?欢迎来 云栈社区 一起深入探讨。




上一篇:37岁老哥拒绝4万月薪,硬耗8个月拿裁员赔偿,值不值?
下一篇:Claude Code 质量事故内部复盘:三个 Bug 如何骗过所有测试
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-5-4 02:01 , Processed in 1.057739 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表