4、显存碎片对推理延迟的影响

各位同学,今天我们来聊聊显存碎片这个“隐形杀手”。

很多人觉得显存碎片就是个存储问题,顶多多占点空间。其实不然。我做过不少推理优化项目,发现碎片对延迟的影响,往往比大家想象的要严重得多。说白了,它会让你的推理服务“慢得莫名其妙”。

4.1 碎片导致的内存分配延迟增加

先问大家一个问题:当你调用 cudaMalloc 申请一块显存时,GPU 在背后做了什么?

答案是:它需要找到一块足够大的连续空闲区域。

如果显存是整齐的,分配就是 O(1) 的操作。但一旦碎片化严重,分配器就得遍历空闲列表,甚至触发内存整理。这个过程,我见过最夸张的案例——一次 cudaMalloc 耗时超过 200 毫秒。

关键数据:

显存状态 平均分配耗时 最大分配耗时
连续(无碎片) ~5 μs ~10 μs
轻度碎片 ~50 μs ~500 μs
重度碎片 ~2 ms ~200 ms

为什么会这样?你想想看,分配器就像在找停车位。停车场空位很多,但都是分散的,你得一个个找。更糟的是,有些分配器还会触发“内存压缩”,把数据挪来挪去——这期间 GPU 计算是停摆的。

我记得有一次线上事故,推理服务的 P99 延迟突然从 20ms 飙升到 500ms。查了半天,发现就是显存碎片导致的分配延迟。嗯,从那以后,我养成了一个习惯:每次上线前,先跑一遍碎片检测脚本。

4.2 内存带宽利用率下降

碎片不仅影响分配速度,还会拖累带宽利用率。这一点,很多工程师容易忽略。

GPU 访问显存时,是以“内存事务”为单位的。理想情况下,一次事务能读取连续的一大块数据。但碎片化之后,数据分布得七零八落,GPU 不得不发起多次小事务来凑齐所需数据。

我的经验: 碎片化严重时,带宽利用率可能从 80% 掉到 30% 以下。你想想,花同样的钱买的 H100,实际跑起来只有三分之一的速度,亏不亏?

具体来说,碎片对带宽的影响体现在三个方面:

  • 非对齐访问增多:碎片导致数据起始地址不按 128 字节对齐,触发额外的内存事务
  • 缓存行浪费:一次读取 128 字节,但其中只有 32 字节是有效数据,其余都是碎片空洞
  • Bank 冲突加剧:碎片分布不均匀,导致显存 Bank 的负载失衡

我曾经优化过一个 Transformer 推理项目。模型本身没问题,但显存碎片导致 attention 计算的带宽利用率只有 25%。我花了三天时间,把张量重新排列,做了显存池化——带宽利用率直接拉到 72%,推理延迟降了一半。

4.3 批处理(Batching)效率降低

批处理是提升推理吞吐量的核心手段。但碎片化会严重限制你的 batch size。

为什么?因为每个请求需要分配独立的显存空间。碎片多了,你很难找到一块足够大的连续空间来容纳整个 batch 的中间结果。结果就是:要么降低 batch size,要么频繁触发内存分配和释放。

注意: 频繁的内存分配/释放会进一步加剧碎片化,形成恶性循环。

我见过一个典型的案例:某团队在做动态批处理时,batch size 从 32 降到 16,吞吐量直接腰斩。他们以为是模型计算量的问题,查了两周才发现是显存碎片在作祟。

这里我给大家一个避坑指南:

  • 预分配策略:启动时一次性申请足够大的显存池,避免运行时频繁分配
  • 张量复用:用缓存池管理中间张量,减少碎片产生
  • 碎片整理:定期检查碎片率,超过阈值时触发整理

我曾经在项目中用过一个简单的碎片检测脚本,分享给大家参考:

def check_fragmentation():
    """检测显存碎片率"""
    free, total = torch.cuda.mem_get_info()
    used = total - free
    
    # 尝试分配不同大小的块
    frag_score = 0
    for size in [1, 4, 16, 64, 256]:  # MB
        try:
            t = torch.empty(size * 1024 * 1024, dtype=torch.uint8, device='cuda')
            del t
            frag_score += 1
        except:
            pass
    
    frag_rate = 1 - frag_score / 5
    print(f"碎片率: {frag_rate:.2%}")
    return frag_rate

这个脚本虽然简单,但能快速定位问题。我建议大家在压力测试时跑一跑,看看碎片率的变化趋势。

小结

显存碎片对推理延迟的影响,总结下来就是三件事:

  • 分配延迟增加,可能从微秒级飙升到百毫秒级
  • 带宽利用率下降,GPU 算力被白白浪费
  • 批处理效率降低,吞吐量上不去

这三个问题往往同时出现,互相放大。所以,做推理优化时,千万别只盯着计算图优化——显存管理这块,同样值得你花时间。

想要更多资料,联系可可