CUDA Toolkit 内存管理全景
一 核心内存空间与生命周期
- 全局内存 Global Memory:所有线程可访问,位于GPU显存,容量大但访问延迟高;生命周期贯穿程序运行,需由开发者显式分配与释放。
- 共享内存 Shared Memory:位于每个 SM 上,线程块内共享,访问延迟低、带宽高,容量小,需手动分块与同步。
- 常量内存 Constant Memory:只读,缓存于各 SM 的常量缓存,适合广播式只读数据。
- 纹理内存 Texture Memory:只读,具备多种寻址与滤波模式,适合空间局部性强的访问。
- 本地内存 Local Memory:线程私有,通常映射到全局内存,用于寄存器溢出或编译器无法放入寄存器的变量。
- 小结:全局/常量/纹理/本地由 CUDA 运行时与硬件管理其分配与可见性;共享内存由程序员在核函数中声明并使用。上述内存类型共同构成 CUDA 的层次化内存模型,是性能优化的基础。
二 分配释放与数据传输 API
- 设备端分配与释放
- cudaMalloc(void devPtr, size_t count):在设备上分配 count 字节的全局内存。
- cudaFree(void devPtr):释放先前分配的设备内存。
- cudaMemset(void devPtr, int value, size_t count):以指定值填充设备内存。
- 主机与设备间传输
- cudaMemcpy(void dst, const void src, size_t count, cudaMemcpyKind kind):在主机与设备间复制数据,kind 可为 cudaMemcpyHostToDevice / DeviceToHost / DeviceToDevice / HostToHost。
- 固定主机内存(Pinned/Paged-locked)
- cudaMallocHost(void ptr, size_t count):分配页面锁定主机内存,可被设备直接访问,H2D/D2H 吞吐更高。
- cudaFreeHost(void ptr):释放固定内存。
- 零拷贝内存(Mapped Pinned)
- 通过 cudaHostAlloc(…, cudaHostAllocMapped) 分配,主机与设备均可直接访问同一映射内存;需做好同步,实际通过 PCIe 远程访问,延迟高、带宽低,适合小数据或调试。
- 统一内存(Unified Memory, UM)
- cudaMallocManaged(void devPtr, size_t size, unsigned int flags = 0):分配托管内存,在 CPU/GPU 间共享同一指针,底层自动迁移数据;简化编程,但性能可能波动。
- 统一虚拟地址 UVA
- 自 CUDA 4.0 起在 64 位系统上提供,使主机与设备共享统一虚拟地址空间,便于指针在 CPU/GPU 间直接传递与比较。
- 性能要点
- PCIe 带宽远低于显存带宽(例如:PCIe Gen2 ≈ 8 GB/s,而 Fermi C2050 GDDR5 ≈ 144 GB/s),应尽量减少主机与设备之间的传输。
- cudaMalloc/cudaFree 开销较高,建议复用设备内存以降低分配成本。
三 访问模式与带宽利用
- 线程束(warp,32 线程)按单条内存请求发出访问;全局内存通过缓存服务,常见事务粒度为128 字节(两级缓存均用)或32 字节(仅二级缓存)。
- 对齐与合并
- 对齐访问:事务首地址为缓存粒度的偶数倍(如 128B/32B)更高效。
- 合并访问:线程束访问连续地址块时,可用最少事务满足需求,带宽利用率最高。
- 优化原则
- 组织数据布局与访问顺序,使线程束访问对齐且连续;必要时利用共享内存/常量内存/纹理内存作为高速缓存,减少全局内存压力。
四 框架层的内存管理实践(以 PyTorch 为例)
- 缓存分配器与延迟释放
- PyTorch 维护 GPU 缓存分配器,对已释放显存进行池化与复用,减少频繁 cudaMalloc/cudaFree 的系统开销,并缓解碎片化。
- 监控与诊断
- 使用 torch.cuda.memory_allocated() / memory_reserved() 观察分配与保留显存;配合 nvidia-smi、PyTorch Profiler、Nsight Systems 定位瓶颈。
- 释放与回收
- 删除不再使用的张量(如 del x),必要时调用 torch.cuda.empty_cache() 清理未使用缓存块(注意:不会释放被张量占用的“已保留”内存)。
- 计算图与推理
- 推理或截断图时用 torch.no_grad();循环中避免无谓的图累积,必要时 detach()。
- 环境与多进程
- 通过环境变量如 PYTORCH_CUDA_ALLOC_CONF 调整分配器策略;多进程训练优先 spawn 启动方式,避免显存状态继承问题。
- 典型优化组合
- 混合精度训练(FP16/BF16)、梯度检查点、动态批处理、必要时 CPU/NVMe Offloading,在显存受限场景显著降低占用并维持吞吐。
五 选型与性能建议
- 大数据高吞吐传输:优先使用普通主机内存 + cudaMemcpy,并批量合并小传输;必要时用固定内存提升 H2D/D2H 带宽。
- 简化开发与通用共享:使用统一内存(cudaMallocManaged),注意其自动迁移可能带来性能波动。
- 小数据/调试或主机内存充足:考虑零拷贝(cudaHostAllocMapped),但需接受高延迟/低带宽。
- 极致带宽与可控性:坚持显存驻留 + 合并访问 + 共享内存/纹理等 GPU 侧优化,尽量减少跨总线传输。