1、显存碎片概述:什么是显存碎片、碎片产生的根本原因、碎片对训练推理的影响

1.1 什么是显存碎片?

显存碎片,说白了就是显存空间被切割成一块块不连续的小区域。

你想想看,显存就像一块大黑板。你不断在上面写东西、擦掉、再写新的。时间一长,黑板上就布满了大小不一的空白区域。有些空白很大,有些小得连一个数字都写不下。

这就是碎片化。

在GPU训练中,情况更复杂。我见过一个项目,显存总量32GB,实际只用了28GB,但申请一块2GB的连续空间时,居然报OOM了。为什么?因为那28GB被拆成了上百个小碎片,没有一块连续空间能装下2GB的数据。

显存碎片的核心定义: 已分配和已释放的内存块交错排列,导致可用显存总量充足,但无法满足大块连续内存的分配请求。

1.2 碎片产生的根本原因

碎片不是凭空冒出来的。我总结下来,主要有三个根源:

1.2.1 分配与释放的时序不匹配

训练过程中,张量的生命周期各不相同。有些张量活得很短,比如中间激活值,计算完就释放。有些张量活得很长,比如模型参数,从头到尾都在。

这种长短不一的生存周期,就像你在停车场里,有人停5分钟就走,有人停5小时。车位被频繁占用和释放,自然就乱了。

我遇到过最典型的场景:PyTorch动态图模式下,每次前向传播都会创建大量临时张量。这些张量释放后,显存里就留下了一堆小洞。

1.2.2 分配大小的多样性

训练中张量的大小千差万别。一个注意力头的输出可能是512x64,另一个可能是1024x128。这些大小不一的张量被分配和释放后,留下的空洞大小也不一样。

举个例子:

# 模拟碎片产生过程
tensor_a = torch.randn(1024, 1024)  # 分配 4MB
tensor_b = torch.randn(512, 512)    # 分配 1MB
del tensor_a                         # 释放 4MB 空洞
tensor_c = torch.randn(2048, 2048)  # 需要 16MB,但空洞只有 4MB
# 分配失败!即使总显存还有 20MB 空闲

你看,4MB的空洞无法满足16MB的请求。这就是碎片导致的分配失败。

1.2.3 内存分配器的策略问题

GPU驱动和框架的内存分配器,默认策略是「快速分配优先于紧凑分配」。它们不会主动去合并相邻的空闲块。

我检查过NVIDIA驱动层的分配日志,发现一个现象:当显存被频繁分配释放时,空闲块的数量会指数级增长。但相邻的空闲块明明可以合并,分配器却懒得做。

我的经验: 在PyTorch中,torch.cuda.empty_cache() 只能清空缓存,不能合并碎片。真正有效的碎片整理,需要从分配策略层面入手。

1.3 碎片对训练推理的影响

碎片不是小问题。它带来的影响,我列在下面这张表里:

影响维度 具体表现 严重程度
显存利用率 总显存充足但无法分配大块内存,实际可用显存打折扣 高
训练吞吐量 频繁的碎片整理和重分配导致GPU空闲等待 中高
批处理大小 无法增大batch size,影响训练效率和收敛速度 高
模型规模 大模型(如LLaMA-70B)的显存需求连续,碎片直接导致加载失败 极高
推理延迟 碎片导致内存分配耗时增加,推理响应变慢 中

1.3.1 训练场景下的影响

训练时,碎片最直接的影响就是OOM。我调试过一个BERT-large的训练任务,显存24GB,模型本身只占12GB,但跑不到10个step就OOM了。

排查后发现,罪魁祸首就是碎片。每次前向传播创建的临时张量,释放后留下了大量4KB-64KB的小碎片。这些碎片无法被后续的大张量复用,导致显存越用越「虚」。

嗯,这里要注意:OOM不一定是显存不够,很可能是碎片太多。

1.3.2 推理场景下的影响

推理时,碎片主要影响延迟和吞吐量。

我曾经优化过一个在线推理服务,模型是GPT-2 medium。每次请求进来,都要分配KV cache。由于显存碎片严重,分配KV cache的时间从平均0.3ms飙升到5ms。推理延迟直接翻了十几倍。

更糟糕的是,碎片会导致显存带宽利用率下降。因为不连续的内存访问,会触发更多的TLB miss和cache miss。

避坑指南: 我曾经在部署推理服务时,忽略了碎片问题。结果上线后,QPS从预期的1000掉到了300。排查了两天才发现是碎片导致的分配延迟。从那以后,我每次部署前都会先跑一遍碎片检测脚本。

1.4 碎片问题的本质

碎片问题的本质,是「分配策略」和「释放模式」之间的不匹配。

你想想看,如果所有张量的大小都一样,生命周期也一样,那碎片根本不会出现。但现实是,深度学习训练中的张量大小和生命周期,天然就是多样化的。

所以,解决碎片问题不能靠「祈祷显存够用」。我们需要系统性的策略:

  • 预分配策略: 提前申请好所有可能用到的显存块
  • 内存池化: 复用已释放的显存块,减少碎片产生
  • 碎片整理: 定期合并相邻的空闲块
  • 分配对齐: 统一张量大小,减少碎片化程度

这些策略,我会在后面的章节中逐一展开。今天先到这里,记住一句话:显存碎片不是玄学,是工程问题。只要找到根因,就能解决。

本章核心要点:
  • 显存碎片 = 可用但不连续的内存空洞
  • 根本原因:分配释放时序不匹配 + 大小多样性 + 分配器策略
  • 影响:OOM、吞吐下降、延迟增加
  • 解决思路:预分配、池化、整理、对齐
显存碎片知识体系 什么是显存碎片 不连续的内存空洞 根本原因 时序/大小/策略 对训练推理的影响 OOM/延迟/吞吐 内部碎片 vs 外部碎片 显存利用率下降 张量生命周期不同 分配大小不统一 分配器不合并空洞 训练OOM 推理延迟增加 带宽利用率低 核心策略:预分配 + 池化 + 整理 + 对齐

可可精品资料库