StackTraces
DeepSeek已驗證

ollama run deepseek-r1:14b 報 out of memory

@debug_master11 天前更新閱讀 6 min00

拉完 deepseek-r1:14b/32b/70b 後第一次推理就 OOM,不一定是模型文件大小問題。三件常被忽略的事疊在一起:預設 keep_alive = 5m 讓上一個模型繼續佔著記憶體;預設 num_ctx = 4096 推高 KV cache;OLLAMA_MAX_LOADED_MODELS 預設允許多個模型併發。把它們都收住,多數機器都能救回來。

Issue & Env(案發現場與環境)

  • 業務場景:本地拉完 deepseek-r1:14b 或 deepseek-r1:32b,跑 ollama run 立刻被 kill,Linux 上 dmesg 報 oom-kill;有時換了一個更小的 tag 反而沒事。
  • 環境:Ollama v0.34.x,DeepSeek-R1 蒸餾模型 Q4_K_M 量化(預設體積 1.5b=1.1GB / 7b=4.7GB / 8b=5.2GB / 14b=9.0GB / 32b=20GB / 70b=43GB),官方上下文窗口統一 128K,671b 主模型 160K。

StackTrace(堆疊日誌)

CUDA 報:

Error: CUDA error: out of memory

進程被系統 OOM killer 幹掉後,Linux 內核日誌會出現:

ollama invoked oom-killer: gfp_mask=0x100cca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

500 形態(服務層把推理進程的死亡包了一下):

500 Internal Server Error: memory layout cannot be allocated

看到這些,先翻 journalctl -u ollama -n 200 --no-pager,裡面會有 Ollama 估算的可用顯存、模型大小、KV cache 佔用分配。

Reproduce(復現程式碼)

最小復現路徑:

# 1) 拉一个比显存/内存大的 tag
ollama pull deepseek-r1:32b       # 20GB

# 2) 先让另一个模型占着内存(默认 keep_alive 5 分钟)
ollama run deepseek-r1:8b --verbose ""  # 然后 bye,模型还在内存里

# 3) 五分钟内再 run
ollama run deepseek-r1:32b
# Error: model requires more system memory than is available
# 或者直接 CUDA error: out of memory

顯存預算粗估:Q4_K_M 量化約 0.6 GB × 十亿参数 + KV cache。14b 想要 ~10GB VRAM,32b 想要 ~20GB,70b 想要 ~43GB。ollama ps 的 SIZE 列加上 VRAM 列就是實際佔用。

Root Cause(根因分析)

OOM 不是一個原因,是多個原因疊在一起。

一、模型本身超過 VRAM/RAM

DeepSeek-R1 蒸餾家族覆蓋 1.5b 到 70b,磁盤體積跟運行時佔用幾乎是 1:1(Q4_K_M 量化需要近乎線性把權重讀到顯存)。32GB 記憶體的機器硬上 32b,能跑但要靠 swap;16GB 上 14b 已經吃緊,70b 直接死。

二、keep_alive 預設 5 分鐘,舊模型沒卸掉

官方 FAQ:By default models are kept in memory for 5 minutes before being unloaded. 這意味著 5 分鐘內連續 run 兩個不同模型,兩個都會佔記憶體。ollama ps 會列出當前駐留的全部。OLLAMA_MAX_LOADED_MODELS 預設是 3 × GPU 数(CPU 推理預設 3),多個模型併發時會同時駐留。

三、num_ctx 4096 預設值推高 KV cache

Ollama 全模型統一預設 num_ctx = 4096,DeepSeek-R1 蒸餾家族最大上下文是 128K。不改預設情況下,KV cache 佔的額外顯存跟上下文長度線性相關。4096 時還能塞進普通機器,8192/16384 起步就開始擠;128K 配 70b,KV cache 就要 80GB+。很多人改了 num_ctx 後第一次跑就崩,其實是把 KV cache 頂上去的。

四、Q4_K_M 量化對精度的取捨

Ollama 庫頁發的是 Q4_K_M(預設)、Q4_K_S、Q5_K_F/Q5_K_M/Q8_0 等不同量化。Q4_K_M 是體積/質量甜點,但 Q8_0 同樣模型能膨脹 1.5–1.7 倍。手動拉 Hugging Face 上的 GGUF 改 Q8_0 時容易撞 VRAM。

五、容器/W SL/記憶體統計口徑不一致

WSL2 預設 VM cap 是 50% 主機記憶體或 8GB 取較小值。64GB 主機跑在 WSL2 裡沒改 .wslconfig,Ollama 看到的是 8GB。Docker 容器 / K8s pod 有 --memory 或 resources.limits.memory 上限,Ollama 只能看到容器內的額度,宿主機再多也幫不上忙。ZFS 文件系統上 ARC 緩存會刻意吃滿空閒記憶體,讓 Ollama 誤判可用 RAM。

The Fix(解決方案)

按便宜程度排序,先試不花錢的。

第一步:先看現在佔著多少

ollama ps

輸出形如:

NAME                ID          SIZE     PROCESSOR  UNTIL
deepseek-r1:8b      ...         5.5 GB   100% GPU   4 minutes from now

UNTIL 列就是 keep_alive 倒計時。

第二步:手動清掉舊模型

ollama stop deepseek-r1:8b
# 或者接口里 keep_alive=0
curl http://localhost:11434/api/generate -d '{"model":"deepseek-r1:8b","keep_alive":0}'

第三步:把 num_ctx 收緊

num_ctx 是 KV cache 的最大頭。不需要長上下文就先收小:

# 临时
ollama run deepseek-r1:14b --num-ctx 2048

# 永久(Modelfile)
cat > Modelfile <<'EOF'
FROM deepseek-r1:14b
PARAMETER num_ctx 2048
EOF
ollama create deepseek-r1:14b-2k -f Modelfile
ollama run deepseek-r1:14b-2k

或者全局把預設值調小:服務側 OLLAMA_CONTEXT_LENGTH=2048。DeepSeek-R1 推薦 temperature 0.6、top_p 0.95,跟預設就夠,num_predict 不需要單獨壓。

第四步:讓 keep_alive 短一點或徹底卸掉

OLLAMA_KEEP_ALIVE=0 讓模型用完立即釋放;想要快速重新加載就 -1 一直駐留:

# systemd drop-in
sudo systemctl edit ollama
[Service]
Environment="OLLAMA_KEEP_ALIVE=0"
sudo systemctl daemon-reload && sudo systemctl restart ollama

第五步:把最大駐留模型數壓到 1

[Service]
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_NUM_PARALLEL=1"

這樣 Ollama 必須先卸舊模型才能加載新的,永遠只有一個佔記憶體。多請求併發在隊列裡等。

第六步:換更小的量化檔或更小的 tag

顯存吃緊時優先選更小的 tag,而不是上 Q4_K_S(不一定發佈)或 Q8_0(更大)。deepseek-r1:14b 用 Q4_K_M ~9GB;deepseek-r1:7b 走 Q4_K_M 是 4.7GB,16GB 記憶體機器也能跑。

GPU 實在不夠就回退到純 CPU:Modelfile 加 PARAMETER num_gpu 0,把模型強制留在記憶體裡運行,速度慢但穩。

第七步:環境側的記憶體可見性

# /etc/modprobe.d/zfs.conf   (限制 ZFS ARC)
options zfs zfs_arc_max=8589934592

# %UserProfile%\.wslconfig   (WSL2 内存上限)
[wsl2]
memory=24GB
swap=8GB

然後 wsl --shutdown 重啟 WSL2。Docker / K8s 同理上調容器 memory。

按這套順序走一遍,out of memory 一般都能收斂。如果還崩,說明機器硬件確實跑不動這個 tag,往下一檔換即可。

References(參考來源)

最後更新於 2026-09-30

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法