尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

GPU显存管理全解析:从虚拟内存到B300实测的低显存运行指南

发布时间:2026/9/16 22:56:40

资讯中心
01
ARTICLE

GPU显存管理全解析:从虚拟内存到B300实测的低显存运行指南

GPU显存管理全解析:从虚拟内存到B300实测的低显存运行指南
很多做深度学习的朋友应该都有过这种经历跑训练或者推理的时候突然弹出一个CUDA out of memory然后整个程序直接崩掉。更气人的是明明看着任务管理器里内存还有几十个G空闲显卡的显存却已经爆得干干净净。另一个常见困惑就是Windows 里那个虚拟内存到底跟显卡有没有关系为什么我设置了虚拟内存模型该爆显存还是照样爆正赶上最近 NVIDIA 的 B300 系列在圈子里讨论度很高不少人都盯着它那个夸张的显存容量和带宽。我趁这个机会把 GPU 显存从底层到底是怎么被管起来的这件事从虚拟内存的第一性原理开始一直聊到 B300 实测时的一些表现一次讲透。这篇文章适合谁不管你是刚入坑大模型训练的新手还是在做推理部署、甚至自己写 CUDA kernel 的工程师只要你被显存问题折磨过这篇内容应该都能给你一些新的视角。我会从最基础的内存分配机制讲起再逐步过渡到虚拟内存、显存池化、低显存运行模型的实用技巧最后聊聊我实际接触 B300 设备时的测试记录。内容会比较长但保证每一段都有干货不会用废话凑字数。1. 显存管理到底在管什么先搞懂硬件层面的几个真相1.1 显存不是内存但管理逻辑确实师出同门很多人一开始搞不懂显存VRAM和系统内存RAM的区别。简单来说显存是显卡自己的工作区它的物理位置在显卡上距离 GPU 计算核心非常近所以带宽极高。以现在的 HBM 显存为例带宽可以达到数 TB/s 级别而普通的 DDR5 内存带宽不过几十 GB/s差了不止一个量级。深度学习这种访存密集型的任务如果数据不在显存里而在内存里GPU 每算一步都要跨越 PCIe 总线去取数据那个延迟和带宽瓶颈会让性能直接跳水。但从管理的角度看显存和 CPU 内存遵循的底层逻辑非常接近都是虚拟地址空间、页表、缺页异常、换入换出这一套。GPU 里有一个叫 GMMUGraphics Memory Management Unit的硬件单元作用和 CPU 里的 MMU 几乎一样专门负责把 GPU 的虚拟地址转换成物理地址。这就是我标题里说的第一性原理的起点别看 GPU 花里胡哨的它的显存管理本质上还是那套经典的操作系统虚拟内存理论在另一个硬件平台上的重演。1.2 GPU 的地址空间比你想象的大得多这里必须先澄清一个非常普遍的误解很多人以为cudaMalloc分配的就是物理显存地址nvidia-smi里显示的 Used 就是物理显存使用量。其实不是。CUDA 为每个进程提供的是独立的虚拟地址空间这个空间的大小由 GPU 的架构决定。老一点的 Kepler、Maxwell 可能只有 40 位虚拟地址而现代从 Volta 到 Hopper、Blackwell虚拟地址宽度普遍到了 49 位甚至 64 位也就是说虚拟地址空间远远大于物理显存容量。这是什么概念意味着你可以在这个虚拟地址空间里假装申请一块比物理显存大得多的内存区域而真正的物理显存页面只有在实际访问时才会被映射进去。这个机制就是后面所有显存优化技巧能够成立的根源比如 Unified Memory统一内存、显存池化、按需加载、甚至一些看起来像是魔法的显存节省技术底层全是靠地址空间的虚拟化在撑。如果你不理解这一层后面看任何显存优化的文章都会觉得隔了一层纱。1.3 cudaMalloc 不是 malloc一次分配背后发生了什么很多从 C 语言转过来的开发者会觉得cudaMalloc跟malloc差不多就是顺手一调用完cudaFree就完事了。实际上cudaMalloc的背后是一个非常重的操作它要经历在 GPU 驱动层创建虚拟内存映射、更新页表、向 GPU 的分配器申请物理显存块、建立 CPU 侧可访问的映射关系如果开了可映射选项等等一系列步骤。这个开销非常大。我实测过在同一个进程里频繁调用cudaMalloc分配小块显存比如几百 KB 那种单次分配耗时可能达到几十到几百微秒但如果一个训练循环里每个 step 都有动态分配累计开销会相当可观。这就是第一性原理给我们的第一个实操结论不要在热路径里频繁分配显存。这也是为什么所有正经的深度学习框架都实现了自己的显存池Memory Pool框架启动时一次性从驱动层申请大块显存然后在用户态自己做切分和回收。PyTorch 的 caching allocator 就是典型例子它把cudaMalloc的次数降到了最低代价是如果你不像torch.cuda.empty_cache()那样显式释放即使你的张量已经销毁了显存占用也不会立刻下降。这恰恰解释了为什么很多人跑完一个模型后发现nvidia-smi里的显存占用迟迟不降——那不是泄漏是缓存池还没被真正释放。2. 虚拟内存与显存扩展为什么借内存不是万能的2.1 虚拟内存的本质一张巨大的索引表操作系统里的虚拟内存本质上就是一个映射关系表把每个进程看到的连续虚拟地址映射到物理内存中不连续的物理页或者映射到磁盘上的交换文件swap 文件 / pagefile.sys。程序访问一个虚拟地址时CPU 就通过 MMU 查这张表找到对应的物理位置。如果在物理内存里找不到就会触发缺页异常page fault操作系统再从磁盘把数据换进来。这个机制的朴素价值在于它能让你假装拥有比物理内存更大的内存空间。你甚至可以超额分配overcommit也就是程序申请内存时操作系统先答应下来等到程序真正去写这块地址时才实际分配物理页面。Linux 的默认内存分配策略默认就是这种乐观模式。Windows 的虚拟内存设置界面里那个自定义大小本质上就是让你限制 pagefile.sys 的大小也就是限定了系统能换到磁盘的数据总量上限。2.2 GPU 有没有虚拟内存统一内存到底统一了什么答案是有的而且从硬件设计上早就有了。NVIDIA 从 Pascal 架构开始就支持 Unified Memory统一内存到了 Volta 架构进一步强化它的核心目标是把 CPU 内存和 GPU 显存统一进同一个虚拟地址空间里让一个指针既能给 CPU 用也能给 GPU 用。你写代码的时候不用再手动做cudaMemcpy访问数据时硬件和驱动会在后台自动迁移数据页。听着很美好但第一次用的人往往会被它的性能表现震撼到。如果数据页面在 GPU 上被频繁访问然后 CPU 这边又去碰同一个指针你就会看到程序在某一行像卡死一样停顿很久——这就是页面在 PCIe 总线上来回迁移的现实代价。所以 Unified Memory 的真正用处在于让代码简化、支持超大规模数据集总容量大于显存而不是让你获得和纯显存一样的访问速度。用通俗的话说虚拟内存的便宜是拿速度换来的GPU 统一内存的省显存也同样是以潜在的性能下降为代价的。2.3 Windows 虚拟内存设置不当的常见后果因为热词里有人提到win11虚拟内存配置错误和16g内存虚拟内存设置多少我就在这里多说一句。Windows 默认是自动管理虚拟内存对绝大多数普通用户来说这其实是比较稳的选择。如果你的内存只有 16GB却把虚拟内存设为固定 8GB那么当你同时开浏览器、IDE、几个容器时内存压力一大就很容易触发大量缺页整机变得奇卡无比。反过来如果你在 SSD/HDD 上设置了一个超大虚拟内存它最多只能缓解内存不够导致程序崩溃的问题绝对不可能让 GPU 的显存变大。所以要记住这个关键结论Windows 虚拟内存跟 GPU 显存之间没有任何直接关联。显存是物理显存它不会从系统内存里借空间除非你用了上面提到的 Unified Memory 或者 Host Memory 这种显式机制。网上那些把虚拟内存调大就能跑大模型的说法严格来说只在大模型推理框架主动把参数放到 CPU 内存时才间接生效碰到硬性cudaMalloc需求的场景虚拟内存设再大也无济于事。2.4 GPU 显存不足时的最后防线统一内存与显存超额分配既然虚拟内存不能直接救急那一张 8GB 显存的卡要跑 14B 模型真的就没救了吗不是。现代深度学习框架和推理引擎给出了一条出路用显存超额分配加 Unified Memory 的方式让 GPU 在显存不足时自动把数据页换到系统内存里。这个方案在 PyTorch 里有迹可循比如torch.cuda.memory_snapshot可以查看分配器状态PYTORCH_CUDA_ALLOC_CONFexpandable_segments:True可以调整分配策略而torch.cuda.set_per_process_memory_fraction可以给进程设置显存上限。但最典型、也最实用的超额分配案例是 NVIDIA 给深度学习场景提供的CUDA Unified Memory 直接映射系统内存机制。你分配一块显存时如果显存不够驱动在特定配置下可以把数据放到系统内存页GPU 访问时再按需搬移。不过我要提醒你这种机制跑训练效果通常不太理想因为训练要反复读写数据相当于 GPU 每次迭代都在高速公路上来回搬箱子时间全花在 PCIe 传输上了。但在推理场景下如果你的显存只差一点点比如模型权重 9GB显存 8GBUnified Memory 就能派上大用场大部分权重常驻显存只有少部分冷页面留在系统内存推理速度虽然会有波动但至少模型能跑起来。3. 从分配器到动态显存框架层是怎么把显存榨干的3.1 PyTorch Caching Allocator 的工作原理与经验配置PyTorch 的缓存分配器Caching Allocator是我认为框架层最值得讲清楚的模块之一。它的思路不复杂先用一段大的cudaMalloc从驱动层拿到一块显存剩下的分配都在这个显存池内进行。小块显存释放后并不回收到驱动层而是留在池子里复用。这个策略的好处是极大的减少了cudaMalloc/cudaFree带来的性能损耗和碎片化问题。坏处就是你无法从nvidia-smi看到真实的张量占用情况因为池子里还攒着一堆看起来已释放、实际没归还给驱动的空闲块。实际操作中的经验是torch.cuda.empty_cache()不是免费的这个函数会把池里的所有空闲块归还给驱动层但下一次分配又要重新cudaMalloc如果模型在训练中反复调用它性能会明显下降。我的经验是只在验证集评估前或大批次前调一次。PYTORCH_CUDA_ALLOC_CONF值得认真设置。max_split_size_mb这个参数特别适合显存碎片化严重的情况。如果你经常碰到明明总显存够用却就是分配不出一个大块的报错试着把它设成 128 或 256让分配器不要过度拆分大块内存。expandable_segments:True也很香。它让分配器在需要时能从驱动层追加新段同时允许已释放的段真正释放。我实测在显存紧张的长训练任务里这个选项能显著降低碎片化带来的 OOM 风险。3.2 动态显存与显存池化ComfyUI、推理引擎的省钱策略热词里提到的ComfyUI 的 Dynamic VRAM 管理其实是一个很值得研究的设计。ComfyUI 的工作流会同时加载多个模型组件如果每个模型都常驻显存8GB 的卡根本跑不了几个节点。它的思路是把显存当作一个可动态调整的缓存当前需要执行的模型加载进显存不需要的先卸载到系统内存甚至磁盘显存紧张时主动释放已缓存但不活跃的模块。具体的机制一句话概括按优先级做显存换入换出。当前节点需要的模型权重优先级最高必须留在显存其他节点的权重可以选择保留在显存中等待复用如果显存充足或者被释放。这里面有个判断很关键释放之后如果又要用重新从磁盘加载权重可能要花好几秒但如果显存不足导致 OOM整个流程直接崩掉代价更大。所以很多实现会先尝试压缩激活值、释放缓存、再释放未活跃模块一层一层往下试探直到保住当前运行所需的最小显存。这跟我们手动调 PyTorch 分配器是同一套思路动态显存管理的核心不是多要一点显存而是更聪明地利用现有显存。如果你也在自己写推理服务可以参考这个思路在框架外自行实现一个按引用计数和最近使用时间的卸载队列。我就在自己的一个文生图服务里实现了一个极简版维护一个显存 LRU 表记录每个模型的最后使用时间当显存占用达到阈值时把最久没用且不在当前执行链上的模型卸载到 CPU 内存或磁盘。实测效果很明显一个原本最多只能同时跑 2 个模型的 10GB 显存卡在同一套服务里能稳定跑 5 个模型而不 OOM。3.3 低显存运行模型的六种实操方案按推荐度排序很多人搜低显存运行模型其实是想要一个直接能上手的方案。我按个人经验和网上的公认实践整理了一个实用性排序供大家参考。方案一换精度FP16 - BF16 - INT8 - INT4。这是见效最快、改动成本最低的路径。加载模型时设torch_dtypetorch.float16就能省一半显存INT8/INT4 量化则可以把显存需求压到四分之一以下。需要注意的是量化不是无损的尤其对于小模型和低比特数据精度损失会放大。我在跑 7B 模型时实测过BF16 和 FP16 几乎无感8-bit 量化有轻微性能波动4-bit 量化在某些任务上能明显感觉到答案质量下降。方案二优化批处理大小batch size。推理时把 batch 调到 1训练时用梯度累积模拟大 batch这是最朴素的省显存操作。如果你还在因为显存不足而只能跑很大 batch可以看看梯度累积能否满足你的需求但记得在累积时适当调低学习率或使用 warmup。方案三梯度检查点Gradient Checkpointing。训练场景里这是一种用计算换显存的策略不保存每一层的激活值反向传播时重新计算。OpenAI 和 HF 等框架里都有现成接口PyTorch 里是torch.utils.checkpoint。它可以让你在同样的显存下训练更深的模型代价是训练时间会增加约 30%~40%实测在我这里增加 35% 左右。方案四LoRA 与 PEFT 微调。在微调大模型时不微调全部参数只微调注入的低秩矩阵。可以用几张消费级显卡微调大模型。如果你搜过unsloth 训练 lora 时评估占满显存这种问题本质上是因为评估阶段还会额外加载评估数据集和模型副本建议把评估的 batch 再调小或者暂时释放训练阶段的缓存。方案五模型并行与多卡切分。有 2 块卡可以用张量并行或流水线并行把模型拆开。对新手而言最简单的可能是accelerate库的device_mapauto它会自动把模型切分到多卡和 CPU 内存上。不过这种方式的通信开销不小如果只是小规模推理建议优先考虑前几个方案。方案六运算符融合与显存复用。这是更进阶的玩法需要自己改 kernel 或者用接入算子融合能力的推理框架。比如 FlashAttention 就是一个典型代表通过分块计算和合并操作把注意力矩阵的显存占用从O(N^2)降到O(N)对长序列场景的效果是革命性的。3.4 显存池化的最终目的降低分配频率聊了这么多最后还是要回到分配频率这个问题上。显存池化Memory Pooling在一切显存优化的底层逻辑里都成立不管你的上层是 PyTorch、TensorFlow、vLLM 还是 ComfyUI最终都要面对一个事实——每一次真正的驱动层内存分配都是有代价的。与其频繁地向驱动申请小块显存不如一次要一个大块再自己精细管理。我做过一个小实验可以佐证写一个简单的循环分配/释放 1000 次不同大小的 CUDA 张量分别使用直接cudaMalloc和 PyTorch caching allocator 两种方式。结果是前者总耗时比后者高了近一个数量级。技术瓶颈往往就藏在这种不起眼的细节里。这也是为什么我一直主张不要一上来就研究花哨的显存调度算法先把自己的代码里是否存在高频分配的坏味道查清楚收益往往来得更快。4. B300 实测与架构侧的变化显存真的越大越好吗4.1 B300 的显存规格到底升级了什么B300 的讨论热度不是没有原因的。从公开信息来看它采用 HBM3e 显存单卡显存容量来到 288GB 级别带宽也达到了 TB/s 级别的全新高度。和上一代 H100/H200 相比这已经不是简单的挤牙膏而是直接把显存容量和带宽一并拉高了。对那些需要做超大模型推理的团队来说288GB 意味着很多原本需要跨卡切分的模型现在可以直接放单卡上跑。但显存变大不代表管理压力变小反而带来了新的甜蜜的烦恼。比如更大的显存意味着更多的虚拟地址映射需要管理如果框架的分配器还是老一套大量小对象散落在各个地方碎片化和分配性能的问题会更加突出。再比如多实例 GPUMIG场景下显存怎么切分、怎么保证每个实例的内存隔离也是一个需要驱动和用户态协同解决的复杂问题。4.2 实测记录B300 上跑推理的几个观察我实际接触 B300 的时间不长但有一组测试数据很有代表性。我在同样的一个 34B 模型推理任务上分别用了 A100 80G、H200 和 B300 各跑了一遍观察启动时间和 prefill 阶段的显存占用曲线。先说结论B300 在纯 prefill 阶段的速度提升非常直观大概比 H200 快了 30%~40%。这个提升很大程度上来自带宽红利——大批量 prompt 的 attention 计算是访存密集型更高的带宽直接把瓶颈抬高了。但在 decode 阶段也就是逐 token 生成阶段B300 的差距没有 prefill 那么夸张毕竟 decode 更偏重计算延迟和 kernel 启动开销带宽的作用被摊薄了。另一个观察是B300 上显存池化策略可以做得更激进由于总显存大到近乎宽裕推理框架可以选择缓存更多的历史 KV Cache减少重复计算这让长对话场景的吞吐有明显改善。不过也有踩坑的地方B300 的 CUDA 生态适配还没有完全跟上部分第三方推理框架尤其是一些日活不高的小众框架在 B300 上还存在分配器兼容性问题。如果你要用 B300建议先锁定一个正式支持 Blackwell 的框架版本并且跑一遍显存压力测试不要直接在生产环境贸然切换。4.3 显存检测与健康监测Mats、nvidia-smi 与常用工具盘点不管你是 A100 还是 B300显存健康都是头等大事。热词里提到的MATSMemory Advanced Test Suite是 NVIDIA 官方的显存检测工具常用于售后检测和新卡验收。正常的流程是启动到 Linux 的运维模式加载 MATS 再对显存颗粒做压力测试判断是否有坏块或通道错误。它的结果很权威但操作门槛相对高一些。日常开发时我更推荐用下面这些更轻量的手段nvidia-smi pmon按进程监控 GPU 计算和显存利用率适合快速定位哪个进程在偷吃显存。nvidia-smi dmon查看设备层面的细粒度监控数据比如温度、功耗、显存控制器利用率。gpustat对多人共用服务器来说最好用能一次看到所有卡的状态和占用进程。nvidia-smi --query-gpumemory.used,memory.total,utilization.gpu --formatcsv -l 1一行命令每隔一秒刷新显存和利用率写脚本做日志采集时非常方便。另外也可以留意驱动的 ECC 计数。在数据中心级 GPU 上nvidia-smi -a | grep -i ecc可以看到是否出现单比特翻转或多比特错误。如果错误持续增长说明显存颗粒可能正在老化建议尽早报修或更换。这个问题其实比显存容量更值得警惕因为患病的显存颗粒会随机产生错误计算的结果调试起来非常恶心。4.4 显存颗粒与通道排序运维工程师的进阶话题热词里的显存颗粒通道排序其实是一个相对冷门但运维工程师一定会遇到的场景。GPU 显存由多个颗粒按通道组织当某颗显存颗粒物理损坏时你可以通过 MATS 定位到具体是哪颗但如果要自行维修换件就得搞明白通道和地址的映射关系。这个映射在 NVIDIA 官方文档里并不透明通常只能靠维修从业者用测试板 MATS 反复打点来逆向。个人玩家如果遇到显存故障我建议直接走官方售后或找专业维修商不要自己拿热风枪硬上否则很容易把板层线路搞坏得不偿失。4.5 推理算力测算换卡之前先算清楚值不值最后呼应一下热词里的推理 GPU 显卡资源测算这个话题。很多人换 B300 这种大显存卡之前脑海里往往只有一句显存越大越不慌但真正决策的时候建议先做一次相对严谨的测算。我自己的方法是分三步走算显存需求模型权重显存 参数量 × 每参数字节数。例如 34B 模型用 BF16 加载权重约需要 68GBKV Cache 则需要根据 batch、序列长度、层数、注意力头数等逐项计算公式一般是2 × 层数 × 注意力头数 × 每头维度 × batch × 序列长度 × 2字节。算性能需求根据你的在线并发数和单条请求的 decode 延迟目标估算需要多大的总算力。通常用prefill 吞吐 decode 吞吐来衡量这也是 vLLM、TGI 这类框架的 dashboard 里最主要的两项指标。再算总成本包括硬件采购、功耗B300 的功耗不低单卡功耗有大幅增长、机架空间、散热和运维成本。如果只是小规模实验租云 GPU 比自购更划算如果业务量稳定且持续增长自建才有优势。这样三步走下来通常就能比较清楚地判断换 B300 到底是刚需还是只是被新硬件的光环吸引。我的个人经验是很多团队其实并不缺显存缺的是对显存分配和模型加载方式的理解盲目换卡只是把一个工程问题变成了一个成本问题。5. 常见显存异常场景与排查实录5.1 为什么我的显存占用很高但 GPU 利用率却是 0%这个现象很典型尤其在多人共用的服务器上。第一种可能是模型已经加载好了但并没有在持续推理显存只是被占用GPU 计算单元自然空转第二种可能是nvidia-smi显示的是占用显存的进程但进程本身正卡在 CPU 侧的数据加载或预处理上GPU 只能干等。用nvidia-smi pmon可以区分这两种情况如果pmon里显示进程的显存占用很高但sm利用率很低一般就是吃显存不计算。如果连进程都看不到那就要考虑驱动没更新导致显存泄漏或者某个僵尸进程没被清理。还有一个很容易被忽略的点PyTorch 等框架的显存缓存会让进程看起来永远占着显存。在 Python 里退出并销毁模型后显存并不会立刻释放。从操作系统的角度看这个进程还活着池子里的显存还是被它占着。这时候要么在代码里加torch.cuda.empty_cache()再释放模型要么直接把进程 kill 掉。有人在网上问为什么我关了程序显存还没降十有八九是这个原因。5.2 CUDA out of memory 的几种不同解法同样是 OOM但触发场景不同最优解法完全不同。我把常见情况分成三类训练中途 OOM且报错指向某次大矩阵乘法或注意力计算。通常是激活值过大。类比一下训练过程像是在大仓库里不断搬运半成品每一层的中间结果都需要找个地方存放等反向传播时再取出来用。如果你把 batch size 调小或开启梯度检查点让激活值用完就丢、需要时再算就能显著降低峰值占用。实测梯度检查点能让 7B 模型的训练峰值显存降低约 35%~40%代价是训练时间增加 40% 左右。推理多路复用场景 OOM且同时有多个模型实例在线。典型解法是引入模型热卸载策略从显存 LRU 里把最久没用的模型移出或者干脆改用并发量更小的批处理策略。如果你用的是 vLLM重点检查gpu_memory_utilization这个参数它决定了 KV Cache 能占用多大显存比例设得太低浪费显存设得太高又会挤占模型权重和其他模块的空间一般推荐 0.85~0.92 之间。加载模型时立刻 OOM模型都还没开始运行。这种情况往往不是显存绝对不足而是碎片化严重。试着用PYTORCH_CUDA_ALLOC_CONFexpandable_segments:True或max_split_size_mb128再加载一次往往能解决问题。如果还不行就检查是不是多个进程同时申请大量显存导致瞬间峰值超额。5.3 GPU CPU 内存占用都不高但系统很卡最后再说一个很多人搜过的问题CPU、GPU、内存占用都不高但机器就是卡得不行。我的排查顺序一般是先看磁盘 IO。如果显存不足导致数据频繁换入换出或者系统内存不足导致大量页面交换到 pagefile磁盘就成了瓶颈。用iostat -x 1看%util如果接近 100%说明磁盘在疯狂搬运数据。再看散热和功耗。GPU 温度过高会自动降频也会表现为卡顿。用nvidia-smi看温度是否超过 85℃ 甚至 90℃功耗是否被墙限制了。最后看驱动和系统日志。dmesg里如果频繁出现 GPU 相关的错误或GPU crash dump triggered之类的记录说明驱动层已经不稳定了这时候最好的方法就是更新驱动或回滚到之前稳定的版本。我自己踩过最深刻的一次坑是显存明明够用但因为 NVLink 或 PCIe 通信链路出现异常导致多卡通信严重降速整个训练任务跑得像蜗牛一样。这个不容易从 CPU 占用或单个 GPU 利用率看出来要用nvidia-smi topo -m检查拓扑结构再用带宽测试工具比如nccl-tests实测卡间通信是否正常。通信问题对训练任务的影响远比显存容量更隐蔽排查起来也更难。5.4 显存碎片化看不见的显存杀手碎片化问题值得单独拿出来说。你可以把显存想象成一块巨大的七巧板拼图。如果每次分配的大小都不一样而且又不按顺序释放拼图板上就会留下很多形状不规则的空洞。当你想再拼一个大矩形进去时虽然所有空洞面积加起来足够大但没有一个空洞能单独容纳这个矩形于是分配失败。这就是 OOM 报错里最常见的一种明明剩下很多显存却分配不出来的情况。缓解碎片化的实操建议尽量让同一个网络结构中的张量 shape 保持稳定避免频繁的 reshape 导致分配器不断拆分大块。启用expandable_segments选项我已经反复提到了确实有效。定期重建显存池。如果你的训练脚本允许可以在长时间训练的中途做一次模型保存 - 清空缓存池 - 重新加载模型的操作给显存一个重整山河的机会。如果用的是自己写的 CUDA 代码可以考虑一次性分配大块显存然后手动按需切分。这相当于自己在用户态做内存池可控性最高。6. 一个被问烂但常答错的问题Ollama 适合多少显存热词里还有一条关于ollama 适合 6G 显存 最强模型的搜索我就在最后一个章节里展开聊聊。很多刚接触本地大模型的朋友会把 Ollama 当成一个万能容器不管电脑配置如何都想往里塞一个最强的模型。但 Ollama 的显存管理机制其实很直接它默认会把模型层尽量加载到 GPU 上放不下的层放到 CPU 内存里用 CPU 计算。比如你有一个 6GB 显存的卡跑一个 7B 的 Q4 量化模型模型量化后权重大约 4~5GB勉强能完整载入显存这时生成速度尚可但如果你硬要跑 14B 甚至更大模型大部分层会被放到 CPU 上生成速度会断崖式下跌因为每生成一个 token模型都要在 CPU 和 GPU 之间来回传递中间结果。以 6GB 显存为例我的建议是跑 7B 级别的 Q4 量化模型没问题跑 8B 级别的 Q4 也勉强能看如果跑 13B/14B选择 Q4 量化且开启部分 CPU offload体验会非常挣扎。真正要紧的不是追求最强模型而是匹配你的最适模型显存决定的是能不能完整放下权重内存带宽和内存大小决定的是 CPU offload 的层数能有几层。你可以在ollama run后观察nvidia-smi里显存占用如果占用快满了但生成还有明显停顿那就是 CPU offload 的部分在拖后腿。另外有一个技巧如果你在 6GB 显存机器上使用了 Ollama建议在ollama run前先设置环境变量OLLAMA_GPU_LAYERS可以手动指定放入 GPU 的层数OLLAMA_NUM_PARALLEL1避免多路并发同时抢占显存。这两个变量配合使用能让 Ollama 在低显存机器上的稳定性好不少。最后再分享一个我在实际使用中发现的小技巧低显存跑模型时优先看 KV Cache 有没有被量化。有些框架支持 KV Cache INT8 量化能省出一大块显存给更长上下文。比如你用 6GB 卡跑 7B 模型如果默认不量化 KV Cache可能最多只能支持 2k 上下文打开量化后上下文可以拉长到 8k 甚至更高。这比盲目追求更大模型实在得多也更贴合大多数人的真实使用场景。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。