vLLM大模型推理:Jetson AGX Thor 的 GPU 共享内存清理实战

适用设备 :NVIDIA Jetson AGX Thor(T5000)实测通过,思路同样适用于 AGX Orin 等采用统一内存架构的 Jetson 设备。


前言

Jetson AGX Thor / Orin 采用 CPU / GPU 统一内存架构(Unified Memory) :显存和内存共用同一块物理 RAM。这带来一个隐蔽的问题------当你关闭 vLLM 等大模型推理服务后,进程明明已经退出,nvidia-smi 也干干净净,但系统内存却被"吃掉"了近百 GiB,迟迟不归还。

本文记录了一次真实排查与回收过程:不重启系统、不重载驱动 ,仅用两条命令回收约 90 GiB 内存。


一、问题描述

现象

在一台 122 GiB 内存的 AGX Thor 上,关闭 vLLM 推理服务后查看内存:

bash 复制代码
$ free -h
               total        used        free      shared  buff/cache   available
Mem:           122Gi        98Gi        11Gi       206Mi        14Gi        24Gi
Swap:             0B          0B          0B
  • ❌ 推理进程已退出,nvidia-smi 没有任何计算进程
  • ❌ 但 used 仍高达 98 GiB ,available 只剩 24 GiB
  • ❌ 即使停止 jtop.service 并重载 nvidia_uvm,内存依旧纹丝不动

根因分析

Thor 的统一内存由驱动/内核统一管理。推理进程退出后,驱动层的可回收内存池(shrinkable caches)并不会立即释放,而是作为缓存保留,等待内核压力回收。

⚠️ 关键认知 :不能仅凭 nvidia-smi 没有进程,就判断内存已全部释放。nvidia-smi 显示的是"活跃分配",而这些残留属于"可回收缓存池"。


二、解决方案

核心思路

通过内核接口 vm.drop_caches=2,主动触发可回收内核缓存的清理------它会调用已注册的 shrinker (当前 NVIDIA 驱动包含 nv_mem_pool_shrinker_count/scan),把空闲的驱动缓存池归还给系统。
#mermaid-svg-nLppZsUlBoVgCoiC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nLppZsUlBoVgCoiC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nLppZsUlBoVgCoiC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nLppZsUlBoVgCoiC .error-icon{fill:#552222;}#mermaid-svg-nLppZsUlBoVgCoiC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nLppZsUlBoVgCoiC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nLppZsUlBoVgCoiC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nLppZsUlBoVgCoiC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nLppZsUlBoVgCoiC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nLppZsUlBoVgCoiC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nLppZsUlBoVgCoiC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nLppZsUlBoVgCoiC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nLppZsUlBoVgCoiC .marker.cross{stroke:#333333;}#mermaid-svg-nLppZsUlBoVgCoiC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nLppZsUlBoVgCoiC p{margin:0;}#mermaid-svg-nLppZsUlBoVgCoiC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nLppZsUlBoVgCoiC .cluster-label text{fill:#333;}#mermaid-svg-nLppZsUlBoVgCoiC .cluster-label span{color:#333;}#mermaid-svg-nLppZsUlBoVgCoiC .cluster-label span p{background-color:transparent;}#mermaid-svg-nLppZsUlBoVgCoiC .label text,#mermaid-svg-nLppZsUlBoVgCoiC span{fill:#333;color:#333;}#mermaid-svg-nLppZsUlBoVgCoiC .node rect,#mermaid-svg-nLppZsUlBoVgCoiC .node circle,#mermaid-svg-nLppZsUlBoVgCoiC .node ellipse,#mermaid-svg-nLppZsUlBoVgCoiC .node polygon,#mermaid-svg-nLppZsUlBoVgCoiC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nLppZsUlBoVgCoiC .rough-node .label text,#mermaid-svg-nLppZsUlBoVgCoiC .node .label text,#mermaid-svg-nLppZsUlBoVgCoiC .image-shape .label,#mermaid-svg-nLppZsUlBoVgCoiC .icon-shape .label{text-anchor:middle;}#mermaid-svg-nLppZsUlBoVgCoiC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nLppZsUlBoVgCoiC .rough-node .label,#mermaid-svg-nLppZsUlBoVgCoiC .node .label,#mermaid-svg-nLppZsUlBoVgCoiC .image-shape .label,#mermaid-svg-nLppZsUlBoVgCoiC .icon-shape .label{text-align:center;}#mermaid-svg-nLppZsUlBoVgCoiC .node.clickable{cursor:pointer;}#mermaid-svg-nLppZsUlBoVgCoiC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nLppZsUlBoVgCoiC .arrowheadPath{fill:#333333;}#mermaid-svg-nLppZsUlBoVgCoiC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nLppZsUlBoVgCoiC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nLppZsUlBoVgCoiC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nLppZsUlBoVgCoiC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nLppZsUlBoVgCoiC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nLppZsUlBoVgCoiC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nLppZsUlBoVgCoiC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nLppZsUlBoVgCoiC .cluster text{fill:#333;}#mermaid-svg-nLppZsUlBoVgCoiC .cluster span{color:#333;}#mermaid-svg-nLppZsUlBoVgCoiC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nLppZsUlBoVgCoiC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nLppZsUlBoVgCoiC rect.text{fill:none;stroke-width:0;}#mermaid-svg-nLppZsUlBoVgCoiC .icon-shape,#mermaid-svg-nLppZsUlBoVgCoiC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nLppZsUlBoVgCoiC .icon-shape p,#mermaid-svg-nLppZsUlBoVgCoiC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nLppZsUlBoVgCoiC .icon-shape .label rect,#mermaid-svg-nLppZsUlBoVgCoiC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nLppZsUlBoVgCoiC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nLppZsUlBoVgCoiC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nLppZsUlBoVgCoiC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 仍有进程
无残留
✅ 明显回收
❌ 无明显变化
关闭 vLLM 服务

停止检测请求
检查残留进程

pgrep -af 'vllm&|EngineCore'
先正常终止进程
确认机器人安全状态

实时控制/GPU任务已停止
sync 落盘
sudo sysctl -w vm.drop_caches=2
free -h 对比验证
完成

恢复 jtop 等监控服务
继续排查进程/驱动占用

禁止强制卸载驱动或重置 GPU

原理解释

要点 说明
✅ 能做什么 通过 shrinker 回收空闲的驱动/内核缓存池
❌ 不能做什么 不是通用 CUDA 显存释放接口;无法释放仍在使用的分配
❌ 不会做什么 不终止进程、不重置 GPU

⚠️ 执行前提 :仅在关闭 vLLM、停止检测请求,并确认机器人处于安全状态、实时控制和其他 GPU 任务已停止后操作。不要在服务刚启动后立即执行。


三、实践示例

以下是终端实录(Thor / JetPack 7.1,L4T 38.4.0,2026-09-14):

bash 复制代码
# ① 回收前:used 98 GiB,available 仅 24 GiB
robot@thor:~/project/vlm_demo$ free -h
               total        used        free      shared  buff/cache   available
Mem:           122Gi        98Gi        11Gi       206Mi        14Gi        24Gi
Swap:             0B          0B          0B

# ② 落盘 + 触发缓存回收
robot@thor:~/project/vlm_demo$ sync
robot@thor:~/project/vlm_demo$ sudo sysctl -w vm.drop_caches=2
vm.drop_caches = 2

# ③ 回收后:used 降至 7.4 GiB,available 达 115 GiB
robot@thor:~/project/vlm_demo$ free -h
               total        used        free      shared  buff/cache   available
Mem:           122Gi       7.4Gi       102Gi       206Mi        14Gi       115Gi
Swap:             0B          0B          0B

效果对比

内存指标 回收前 回收后 变化
系统总内存 122 GiB 122 GiB ---
已用 used 98 GiB 7.4 GiB ↓ 约 90 GiB ✅
空闲 free 11 GiB 102 GiB ↑ 91 GiB
可用 available 24 GiB 115 GiB ↑ 91 GiB ✅
缓存 buff/cache 14 GiB 14 GiB 不变

一次手动执行,约回收 90 GiB,无需重启系统、无需关闭桌面。 该结果强烈支持"可回收驱动/内核内存池"的解释。


注意事项(务必阅读)

  • 🔸 操作顺序 :本次实测前曾停止 jtop.service 并重载 nvidia_uvm,但均无效;缓存回收才是真正生效的一步 。下次遇到相同现象,请优先测试缓存回收,不要先重载驱动(尚未验证省略前置操作的效果)。
  • 🔸 一次性操作:回收会造成短暂卡顿和缓存重建开销。❌ 不要循环执行、❌ 不要设置定时清理、❌ 不要写入永久 sysctl 配置。
  • 🔸 回收无效时:继续排查进程与驱动占用,❌ 不要强制卸载 NVIDIA 驱动,❌ 不要直接重置 GPU。
  • 🔸 善后 :若此前停止了 jtop 后台服务,检查结束后执行 sudo systemctl start jtop.service 恢复监控。
  • 🔸 诚实声明 :尚未逐项追踪具体内存池,也不能据此认定退出日志中的 EngineDeadError 是内存占用的原因。

总结

步骤 命令
1️⃣ 确认无残留进程 `pgrep -af 'vllm
2️⃣ 记录回收前状态 free -h
3️⃣ 落盘 sync
4️⃣ 触发回收 sudo sysctl -w vm.drop_caches=2
5️⃣ 验证 free -h

一句话记住 :Thor/Orin 统一内存下,服务关了 ≠ 内存还了;sync + vm.drop_caches=2,安全回收驱动缓存池。

分享完成~

相关推荐
缘友一世10 小时前
GLM5.3 flash cybersec本地部署[4]:基准测试与复现
vllm·glm5.3 flash
rjc_lihui1 天前
NCCL,Tokio ,vLLM ,Vue 3在线书籍
vllm
GPUStack1 天前
一张 A800 80GB,跑通 Qwen-Image-2.1:GPUStack 部署、生成与图像编辑实战
人工智能·开源·github·vllm·大模型部署·gpustack
缘友一世2 天前
GLM5.3 flash cybersec本地部署[0]:环境准备与首次启动
vllm·glm5.3 flash
山顶夕景2 天前
【VLM】DeepSeek-V4.1-Flash: Pushing the Limits of KV Cache Compression
多模态·kv·vlm·infra
头发够用的程序员2 天前
TensorRT 自定义算子插件实战(三):手搓 2×2 最大池化 customMaxpool
人工智能·pytorch·python·深度学习·神经网络·边缘计算·jetson
DongQiShanRen3 天前
裁决台账双向互校(中):五向一致性链——②向解读与③向实现
人工智能·深度学习·自然语言处理·集成学习·vllm
智码看视界3 天前
开源大模型每日追踪:小米 MiMo-V2.6-Pro,登顶开放权重第一(超过 GLM-5.3 、Kimi K3)
agent·vllm·moe·全模态·小米大模型·mimo-v2.6
山顶夕景4 天前
【VLA】Qwen-VLA:VLM+DiT统一多模态理解与连续机器人动作生成
机器人·多模态·扩散模型·具身智能·vla·dit·vlm
零基础1235 天前
DeepSeek V4.1 Flash (Batch) 的性能测试与应用
经验分享·python·语言模型·vllm