4、环境准备:安装vLLM、配置GPU环境、监控工具介绍

在开始定位显存泄漏之前,必须先搭建一个可观测、可复现的实验环境。显存泄漏的排查高度依赖版本一致性、GPU 运行状态的可视化以及进程级显存数据的采集能力。本节将围绕 vLLM 安装、GPU 环境配置和监控工具链三个部分展开,确保后续章节中的每一项诊断操作都有可靠的环境支撑。

4.1 安装 vLLM:版本锁定与依赖隔离

vLLM 对 CUDA、PyTorch 和 Python 版本有严格约束。推荐使用 Python 3.10+ 和 CUDA 12.1 作为基线,并通过虚拟环境隔离依赖。安装时务必锁定版本,避免因依赖升级引入隐性显存行为变化。

# 创建虚拟环境
python3.10 -m venv /opt/vllm-env
source /opt/vllm-env/bin/activate

# 安装 PyTorch(与 CUDA 12.1 匹配)
pip install torch==2.3.0 torchvision==0.18.0 --index-url https://download.pytorch.org/whl/cu121

# 安装 vLLM(锁定版本)
pip install vllm==0.5.4

# 验证安装
python -c "import vllm; print(vllm.__version__)"
版本一致性提示:生产环境与排查环境必须使用完全相同的 vLLM、PyTorch、CUDA 驱动版本。显存泄漏往往与特定版本的缓存管理逻辑相关,版本漂移会导致复现失败。

4.2 配置 GPU 环境:显存可见性与进程隔离

GPU 环境配置的核心目标是让显存分配行为透明化。需要从三个层面进行配置:驱动层、运行时层、进程层。

  • 驱动层:确认 NVIDIA 驱动版本 ≥ 535,使用 nvidia-smi 验证 GPU 拓扑和显存总量。
  • 运行时层:设置 CUDA_VISIBLE_DEVICES 固定单卡,避免多卡间显存分配干扰。
  • 进程层:使用 ulimit -v unlimited 解除虚拟内存限制,防止 OOM Killer 误杀排查进程。
# 设置 GPU 可见性(单卡排查)
export CUDA_VISIBLE_DEVICES=0

# 启用 CUDA 内存分配日志(关键)
export CUDA_LAUNCH_BLOCKING=1
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True

# 查看 GPU 状态
nvidia-smi --query-gpu=index,name,memory.total,memory.used,memory.free --format=csv
注意:PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True 会改变显存分配策略,使 PyTorch 缓存块可扩展。该配置在排查碎片化泄漏时非常有效,但会略微增加显存占用,需在实验前固定该参数。

4.3 监控工具介绍:从全局到进程级

显存泄漏排查需要三层监控数据:全局 GPU 状态、进程级显存分配、PyTorch 缓存内部视图。以下工具组合覆盖全部三个层次。

工具 监控层次 核心能力 输出形式
nvidia-smi 全局 GPU 显存总量、已用、进程列表 CLI 表格
nvitop 全局 + 进程 实时刷新、按显存排序、历史曲线 交互式 TUI
py-spy Python 进程 采样 Python 调用栈,定位分配点 火焰图 / 文本
torch.cuda.memory PyTorch 缓存 缓存块、分段、保留内存明细 Python API
gpu-burn 压力测试 验证 GPU 硬件稳定性 CLI 日志

其中 torch.cuda.memory 是定位泄漏的核心工具,它能展示 PyTorch 缓存分配器的内部状态,区分缓存占用与实际张量占用。以下代码片段展示了如何采集关键指标:

import torch
import vllm

def snapshot_memory():
    # 当前缓存分配器状态
    allocator_stats = torch.cuda.memory_stats()
    print(f"当前分配: {allocator_stats['current_bytes_allocated'] / 1024**2:.1f} MB")
    print(f"缓存保留: {allocator_stats['current_bytes_reserved'] / 1024**2:.1f} MB")
    print(f"活跃段数: {allocator_stats['num_active_segments']}")
    
    # 显存快照(JSON 格式)
    snapshot = torch.cuda.memory_snapshot()
    print(f"快照段数: {len(snapshot)}")
    
    # 打印每个段的关键信息
    for seg in snapshot[:5]:
        print(f"  段大小: {seg['size'] / 1024**2:.1f} MB, "
              f"活跃: {seg['active_size'] / 1024**2:.1f} MB, "
              f"分配器: {seg['segment_type']}")

# 在 vLLM 推理前后调用
snapshot_memory()

4.4 监控架构与数据流

为了直观理解各监控工具在排查流程中的位置,下图展示了从 GPU 硬件到 Python 进程的完整监控数据流。图中左侧为硬件层,中间为运行时层,右侧为应用层,箭头表示监控数据的采集方向。

GPU 显存监控数据流架构 硬件层 NVIDIA GPU (显存 80GB) CUDA Driver (≥535) 运行时层 PyTorch 缓存分配器 vLLM 显存管理器 应用层 vLLM 推理服务 Python 监控脚本 监控工具层 nvidia-smi nvitop py-spy memory_snapshot gpu-burn 显存分配 张量访问 CLI 查询 API 调用 进程采样 关键监控路径: ① nvidia-smi 监控硬件层显存总量 → ② PyTorch memory_snapshot 查看缓存分配器内部段状态 → ③ py-spy 定位 Python 层分配调用栈 → ④ 对比多时间点快照识别泄漏趋势

上图展示了监控数据从 GPU 硬件到 Python 应用的分层流动路径。在实际排查中,nvidia-smi 负责确认显存总量是否持续增长,memory_snapshot 用于区分缓存保留与真实占用,py-spy 则帮助定位是哪个 Python 调用触发了显存分配。三层数据相互印证,才能准确判断泄漏发生在 vLLM 内部还是外部代码。

4.5 环境验证与基线采集

环境配置完成后,必须执行一次基线验证,记录正常状态下的显存指标,作为后续泄漏判断的参照。建议执行以下步骤:

  1. 启动一个最小 vLLM 推理任务(加载一个小模型,如 facebook/opt-125m)。
  2. 连续执行 50 次推理请求,每 10 次记录一次显存快照。
  3. 确认显存曲线在初始增长后趋于平稳,波动范围不超过 2%。
  4. 保存基线数据到 JSON 文件,便于后续对比。
# 基线采集脚本示例
import json
import time
import torch
from vllm import LLM, SamplingParams

llm = LLM(model="facebook/opt-125m", gpu_memory_utilization=0.7)
params = SamplingParams(temperature=0.8, max_tokens=64)

baseline = []
for i in range(50):
    output = llm.generate("Hello, world!", params)
    stats = torch.cuda.memory_stats()
    baseline.append({
        "step": i,
        "allocated_mb": stats["current_bytes_allocated"] / 1024**2,
        "reserved_mb": stats["current_bytes_reserved"] / 1024**2,
        "active_segments": stats["num_active_segments"]
    })
    time.sleep(0.5)

with open("baseline_memory.json", "w") as f:
    json.dump(baseline, f, indent=2)
print("基线数据已保存至 baseline_memory.json")
基线判断标准:正常环境下,reserved_mb 在预热后应保持稳定,active_segments 数量不应持续增长。若连续 20 次请求后 reserved 值单调递增且无回落,则高度怀疑存在显存泄漏,需进入下一章的详细诊断流程。

4.6 常见环境配置误区

在环境准备阶段,以下误区会直接影响后续排查的准确性,需要特别注意:

  • 误区一:使用最新版 vLLM。最新版可能引入未稳定的显存管理逻辑,建议锁定稳定版本(如 0.5.x),排查完成后再升级。
  • 误区二:忽略 CUDA 缓存清空。PyTorch 的 torch.cuda.empty_cache() 只释放缓存块,不改变分配器保留内存,不能作为泄漏判断依据。
  • 误区三:多卡环境未隔离。多卡并行时显存分配可能跨设备,导致单卡监控数据失真,排查时必须固定单卡。
  • 误区四:缺少基线数据。没有基线就无法判断显存增长是正常预热还是异常泄漏,务必在环境搭建后立即采集。