ggml-backend: discarded ggml_gallocr_reserve_n return value turns an allocation failure into a segfault

这个报错通常发生在 llama.cpp 显存/内存分配失败时: ggml_backend_sched_alloc_splits 丢弃了 ggml_gallocr_reserve_n 的返回值,导致 reserve 失败后仍继续执行 ggml_gallocr_alloc_graph ,最终从本应返回错

快速结论:这个报错通常发生在 llama.cpp 显存/内存分配失败时:ggml_backend_sched_alloc_splits 丢弃了 ggml_gallocr_reserve_n 的返回值,导致 reserve 失败后仍继续执行 ggml_gallocr_alloc_graph,最终从本应返回错误变成段错误(segfault):ggml-backend: discarded ggml_gallocr_reserve_n return value turns an allocation failure into a segfault。优先排查是否在长 prompt、ubatch 较大或显存不足的场景下触发。

适用环境:Issue 中确认的环境为 llama.cpp CUDA 构建,Ubuntu 24.04,驱动 595.71.05,CUDA 13.0.88,2x RTX 3090 24 GiB,54 GiB 主机内存无 swap,CMAKE_CUDA_ARCHITECTURES=86,代码来自 unslothai/llama.cppqwen4exp/qwen3.8-flash-next 分支 6c5afc8(PR #27742);评论中还确认了 Apple Metal 上的 transcribe.cpp 复现路径。

最快修复方案:暂无确认的一步修复方案;Issue 中的修复思路是把 ggml/src/ggml-backend.cpp:1586 处的 ggml_gallocr_reserve_n 调用包进 if (!...) 判断并返回 false,使失败走 GGML_STATUS_ALLOC_FAILED 错误路径,相关 PR 为 #27855;该修复思路在提交时尚未验证。

注意事项:该改动只解决“分配失败被吞掉后变成 segfault”,不会降低显存占用,也不会让原本 OOM 的配置变得可用;作者明确说明该补丁未经运行验证,只是阅读周边代码后的提案。评论中列出多个相关 PR(#26070、#27855、#28149),需要等待合并确认。

问题场景

用户在 llama.cpp 的 llama-server 上运行 Qwen3.8-Flash-Next(PR #27742,qwen4exp),使用 2x RTX 3090,将 routed experts 拆分到两张卡和主机内存。服务能正常加载,短 prompt 能正确回答,但在处理长 prompt 时中途崩溃。复现三次分别发生在 17849、26624 和 59392 tokens,涉及两种不同的 expert 放置方式,以及 -ub 2048-ub 1024 两种配置。

报错原文

prompt processing, n_tokens = 17849, progress = 0.90, t = 36.54 s / 488.50 tokens per second
ggml_backend_cuda_buffer_type_alloc_buffer: allocating 1599.01 MiB on device 1: cudaMalloc failed: out of memory
ggml_gallocr_reserve_n_impl: failed to allocate CUDA1 buffer of size 1676685440
Segmentation fault

ggml-backend: discarded ggml_gallocr_reserve_n return value turns an allocation failure into a segfault

原因分析

最可能的原因是 ggml/src/ggml-backend.cpp:1586 处的 ggml_gallocr_reserve_n 调用没有检查返回值。该函数声明为 bool,并在 ggml-alloc.h:64 中说明缓冲区分配失败时返回 false。当 CUDA 分配失败时,reserve 操作让 allocator 处于部分初始化状态,代码却继续调用 ggml_gallocr_alloc_graph,最终触发段错误,而不是通过已有错误路径返回。相同调用在 ggml-backend.cpp:1929 处有检查,只有 line 1586 丢弃了返回值。

另一个促成因素是 qwen4exp 的 sparse attention bias 输入大小为 [n_kv, n_tps, n_stream],因此 compute buffer 会随实际处理的 prompt 长度增长,而不是随 -c 增长。这意味着一套能正常加载、能回答短 prompt 的配置,仍可能在长 prompt 时耗尽显存,然后从“报错”变成“段错误”。

环境排查

  • 确认 llama.cpp 构建来源与 commit:Issue 中为 unslothai/llama.cpp 分支 qwen4exp/qwen3.8-flash-next,commit 6c5afc8(PR #27742)。
  • 确认 CUDA 构建配置:CUDA 13.0.88(构建描述中另提到 13.0.2)、CMAKE_CUDA_ARCHITECTURES=86
  • 确认显卡与显存:2x RTX 3090,每张 24 GiB,主机 RAM 54 GiB,无 swap。
  • 确认操作系统与驱动:Ubuntu 24.04,驱动 595.71.05。
  • 确认运行参数:-ngl 99 -sm layer -fit off -c 32768 -fa on -ctk f16 -ctv f16 -b 2048 -ub 2048 -t 8,以及 -ot 指定的 CPU 卸载规则。
  • 如果使用 Apple Metal,评论中确认在 transcribe.cpp 上也能复现类似 OOM 崩溃,涉及 Metal buffer 分配失败。

解决步骤

  1. 先确认触发条件:是否在长 prompt 处理过程中、显存接近耗尽时出现 cudaMalloc failed: out of memory 或 Metal 的 failed to allocate buffer,随后进程直接崩溃且没有 Compute error. 之类的错误输出。
  2. 降低显存压力作为临时规避:减少 -c、降低 -ub、调整 -ot 将更多层放到 CPU,或减少并发/批量处理,避免在长 prompt 时触发分配失败。
  3. 可优先尝试 Issue 中提出的代码修复:在 ggml/src/ggml-backend.cpp:1586 处把 ggml_gallocr_reserve_n(...) 包进 if (!...) 判断,失败时记录 failed to reserve graphreturn false,让错误走 GGML_STATUS_ALLOC_FAILED 路径,而不是继续进入 ggml_gallocr_alloc_graph
  4. 关注相关 PR 的合并状态:评论中列出了 #26070、#27855、#28149,并建议合并为一个经过审查的补丁;在合并前不要把该修复当成已发布的稳定行为。
  5. 如果需要在本地验证修复方向,按 Issue 中的 repro 构建相应分支,并发送约 18000 tokens 的 prompt 来触发;注意该补丁本身不改变显存占用,只是把崩溃变成可处理的分配失败错误。

验证方法

应用修复后,再次触发相同的长 prompt 分配失败场景,预期不再出现 Segmentation fault,而是看到 failed to reserve graphfailed to allocate graph 之类的错误日志,并通过 llama.cpp 已有错误路径返回 GGML_STATUS_ALLOC_FAILED,最终在 server 侧表现为 Compute error. 并释放槽位,而不是进程直接崩溃。

参考来源

ggml-org/llama.cpp #27817

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 24332

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注