mmap 和 DMA-BUF 在零拷贝技术上的区别
在 Linux 系统中,mmap
和 DMA-BUF
都是实现 零拷贝(Zero-Copy) 的关键技术,但它们的应用场景、设计目标和实现方式有显著差异。以下是两者的对比:
📌 1. 核心概念
技术 | 主要用途 | 适用场景 |
---|---|---|
mmap | 将 文件/设备内存 映射到 用户进程虚拟地址空间,允许直接访问。 | 文件 I/O、显存映射、进程间共享内存。 |
DMA-BUF | 提供 跨驱动/设备的缓冲区共享框架,允许不同硬件(如 GPU、摄像头、编码器)直接共享内存,无需拷贝。 | 多媒体流水线(如摄像头→GPU→显示器)。 |
📌 2. 零拷贝的实现方式
(1) mmap
的零拷贝
-
机制:
通过内存映射,用户进程直接访问 内核管理的物理内存(如文件页缓存、GPU 显存),避免数据在用户态和内核态之间的拷贝。 -
示例:
- 文件读取:
mmap
文件后,应用直接读写页缓存,无需read()
/write()
。 - GPU 显存:DRM 驱动通过
mmap
将显存映射到用户空间,渲染程序直接操作。
- 文件读取:
-
优点:
- 减少 CPU 拷贝开销。
- 适用于 单设备内 的零拷贝(如 CPU 访问 GPU 显存)。
- 应用比较广泛,使用大部分简单的zero-copy场合
-
缺点:
- 无法跨设备共享:
mmap
的缓冲区通常仅对当前设备有效(如 GPU 显存无法直接用于摄像头硬件)。 - 缺乏同步机制:需手动处理 CPU/GPU 缓存一致性(如
msync
或 DRM 的原子提交)。
- 无法跨设备共享:
(2) DMA-BUF
的零拷贝
-
机制:
- DMA-BUF 是一个 共享内存的标准化接口,核心是
struct dma_buf
,代表一块可跨设备共享的物理内存。 - 通过 文件描述符(fd) 传递缓冲区,支持跨进程、跨驱动、跨硬件访问。
- 依赖 DMABUF Heaps 或 DRM/KMS 分配内存。
- DMA-BUF 是一个 共享内存的标准化接口,核心是
-
示例:
- 摄像头→GPU→显示器流水线:
- 摄像头驱动分配 DMA-BUF 缓冲区(
/dev/dma_heap/system
)。 - 通过
fd
将缓冲区传递给 GPU 驱动(如 OpenGL/Vulkan)。 - GPU 渲染后,同一
fd
传递给显示控制器(KMS)直接输出。
- 摄像头驱动分配 DMA-BUF 缓冲区(
- 摄像头→GPU→显示器流水线:
-
优点:
- 真正的跨设备零拷贝:GPU、VPU、摄像头等硬件直接访问同一块物理内存。
- 内置同步机制:通过
fence
(同步原语)保证设备间读写顺序。 - 标准化:所有主流 Linux 驱动(DRM、V4L2、Media)均支持 DMA-BUF。
-
缺点:
- 需要驱动支持(旧硬件可能不兼容)。
- 用户态需处理
fd
的传递和管理。
📌 3. 关键区别总结
特性 | mmap | DMA-BUF |
---|---|---|
设计目标 | 用户态直接访问内核内存 | 跨设备/驱动的内存共享 |
共享范围 | 单进程或进程间(需显式设置) | 跨进程、跨设备(通过 fd 传递) |
同步机制 | 需手动处理(如 msync ) | 内置 fence 同步(自动协调设备访问) |
硬件支持 | 通用(所有文件/设备) | 需驱动支持(如 DRM、V4L2) |
典型用例 | 文件映射、GPU 显存访问 | 摄像头→GPU→显示器的多媒体流水线 |
性能 | 减少 CPU 拷贝,但限于单设备 | 真正的跨设备零拷贝 |
📌 4. 如何选择?
-
用
mmap
当:- 只需要 CPU 访问文件或设备内存(如 GPU 显存)。
- 不涉及多设备协作。
-
用
DMA-BUF
当:- 需要 多个硬件模块(GPU、摄像头、编码器)共享同一块内存。
- 需要自动同步(如 GPU 渲染完成后,显示器再读取)。
📌 5. 代码示例对比
(1) mmap
实现零拷贝(GPU 显存)
// DRM 分配显存并 mmap 到用户空间
struct drm_mode_create_dumb create_arg = { .width=1920, .height=1080, .bpp=32 };
ioctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
void *map = mmap(NULL, create_arg.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, create_arg.handle);
// 直接操作 map 渲染...
(2) DMA-BUF
实现跨设备零拷贝
// 从 DMA-BUF Heap 分配缓冲区
int dma_heap_fd = open("/dev/dma_heap/system", O_RDWR);
struct dma_heap_allocation_data alloc = { .len = 1024*1024 };
ioctl(dma_heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
// 将 fd 传递给 GPU 驱动(如 Vulkan)
VkImportMemoryFdInfoKHR import_info = { .fd = alloc.fd, ... };
vkAllocateMemory(device, &import_info, ...);
// 同一 fd 可传递给其他设备(如摄像头或显示器)
📌 6. 总结
mmap
:
单设备零拷贝,适合 CPU 直接访问文件或设备内存(如 GPU 显存),但无法跨硬件共享。DMA-BUF
:
跨设备零拷贝,通过标准化fd
和fence
实现多媒体流水线的高效内存共享。
现代图形/多媒体栈的核心技术(如 Wayland、GStreamer、ML 推理)。
若需最大化性能(如摄像头→GPU→显示器的 4K 流水线),DMA-BUF 是唯一选择。
DMA-buf技术来自Samsung的drm驱动开发人员,提出该框架后很快merge到linux drm主线,并在v4l2,drm等展开应用。