显存基础:GPU显存架构、带宽与容量、分配与回收机制
大家好,我是你们的老朋友。今天咱们聊聊显存——这个在吞吐压测里最容易出幺蛾子的家伙。
说实话,我见过太多团队,模型跑得挺欢,一上压测就崩。查到最后,十有八九是显存管理出了问题。你想想看,显存就像GPU的“工作台”,东西摆不下,再好的算法也白搭。
一、GPU显存架构:从芯片到板卡
先说说显存长什么样。嗯,这里要注意,显存不是一块独立的内存条,它是焊在显卡PCB板上的颗粒。
目前主流的显存类型是GDDR6和HBM2e。GDDR6常见于消费级显卡,比如RTX 3090、4090。HBM2e则多用于数据中心卡,像A100、H100。
我个人习惯把显存架构分成三层来看:
- 物理层:显存颗粒本身,决定了总容量和位宽
- 控制器层:显存控制器,负责调度读写请求
- 缓存层:L1/L2缓存,减少对显存的直接访问
我在项目中遇到过一件事:某次压测,模型推理速度忽快忽慢。查了半天,发现是L2缓存命中率太低,导致频繁访问显存。说白了,缓存没用好,带宽再大也白费。
核心要点:显存架构的瓶颈往往不在容量,而在带宽和延迟。压测时,先看缓存命中率,再看显存带宽利用率。
二、显存带宽与容量:两个关键指标
带宽和容量,这两个参数经常被混为一谈。其实它们管的是不同的事。
带宽决定了数据搬运的速度。计算公式很简单:
显存带宽 = 显存频率 × 位宽 × 2(GDDR双倍数据率)
举个例子:
RTX 4090:频率 21 Gbps,位宽 384-bit
带宽 = 21 × 384 / 8 = 1008 GB/s
容量决定了你能装下多大的模型。比如一个70B的LLaMA模型,用FP16加载,光权重就要140GB。你想想看,单卡24GB显存根本装不下。
实战技巧:我建议压测前先算一笔账——模型权重 + 优化器状态 + 中间激活值 + 临时缓冲区。这四个加起来,别超过显存容量的80%。留点余量,不然跑着跑着就OOM了。
| 显卡型号 | 显存容量 | 显存带宽 | 适用场景 |
|---|---|---|---|
| RTX 3090 | 24 GB | 936 GB/s | 单卡推理、小模型训练 |
| RTX 4090 | 24 GB | 1008 GB/s | 高吞吐推理、中等模型 |
| A100 80G | 80 GB | 2039 GB/s | 大模型训练、多卡并行 |
| H100 | 80 GB | 3352 GB/s | 超大模型、专家并行 |
我曾经踩过一个坑:压测时只看容量,没注意带宽。结果模型是装下了,但推理速度慢得像蜗牛。后来一查,带宽利用率飙到95%,明显是带宽瓶颈。说白了,容量管“能不能装”,带宽管“快不快”。
三、显存分配与回收机制:别让内存泄漏坑了你
这个部分,我觉得是压测里最容易翻车的地方。显存分配和回收,说白了就是操作系统那套“malloc/free”的GPU版。
CUDA里,显存分配主要靠这几个API:
cudaMalloc:分配显存,返回设备指针cudaFree:释放显存cudaMallocManaged:统一内存,自动迁移
但问题来了——频繁调用cudaMalloc和cudaFree,性能会非常差。为什么?因为每次分配都要和驱动交互,开销很大。
避坑指南:我曾经在压测脚本里每轮迭代都cudaMalloc一次,结果显存碎片化严重,跑了200轮就OOM了。后来改用显存池(memory pool),一次性分配一大块,自己管理,性能提升30%以上。
显存回收还有个坑:Python的垃圾回收和CUDA显存回收是异步的。你调了del tensor,显存不会立刻释放。得等cuda.synchronize()之后才真正回收。
# 错误示范
import torch
for i in range(1000):
x = torch.randn(1024, 1024).cuda()
# 没有显式释放,显存越占越多
# 正确做法
for i in range(1000):
x = torch.randn(1024, 1024).cuda()
# 用完就删
del x
torch.cuda.empty_cache() # 建议加上,但别频繁调用
嗯,这里要注意:empty_cache()也不能频繁调,因为它会清空缓存,下次分配又要重新申请,反而降低性能。我个人的习惯是:每100轮调一次,或者显存占用超过80%时触发。
总结一下显存管理的三个原则:
- 预分配 > 按需分配(用显存池)
- 及时释放 > 依赖GC(手动del)
- 监控碎片 > 只看总量(用nvidia-smi看碎片率)
好了,显存基础就聊到这儿。记住,压测不是跑起来就行,得把显存吃透。下节课咱们聊聊怎么用工具监控显存,到时候我会分享几个我压箱底的脚本。
课后小作业:打开nvidia-smi,看看你的显卡显存带宽和容量。再跑一个模型,观察显存分配和释放的过程。试试看,能不能找到碎片化的迹象?