海外雲在線 海外雲在線 立即諮詢

GCP帳號充值服務 GCP內存溢出OOM崩潰排查與解決:如何增加 Swap 虛擬記憶體防死機

谷歌雲GCP / 2026-09-01 15:01:39

第一章:為什麼 GCP 的 OOM 不是你想的那麼單純

你以為 OOM 就是「記憶體不夠」,但在 GCP 上,真正導致服務崩潰的原因常常是更細的邊界:容器的 cgroup 限制、虛擬記憶體策略、應用程式的記憶體分配方式、以及是否啟用了 Swap。尤其在 Compute Engine、GKE(Kubernetes)或其他以容器為核心的服務上,OOM Killer 的觸發條件不只取決於整機記憶體,還取決於「你被允許使用多少」。

當應用因為 OOM 被系統終止,表面看起來像是「瞬間崩潰」,但其實通常是某個時間窗內記憶體持續上升、達到限制後被直接殺死。這種情況如果不處理根因,只靠重啟或擴容會反覆發生,且成本越滾越高。

本文會用一個務實的思路:先把崩潰的觸發點對齊到「是哪個層級在限制記憶體」,再用 Swap 作為緊急緩衝,讓服務在記憶體壓力下更有機會自救或至少避免立刻死掉,同時也提出長期修復路線。

第二章:先判斷你看到的是哪種 OOM

排查 OOM 最怕的不是找不到資料,而是把不同類型混在一起。建議你先做三件事:確認事件時間、確認是進程被殺、確認是節點還是容器層級。

2.1 觀察系統層與應用層的關聯時間

通常你會有:負載突然上升、延遲變大、或某次任務批量處理後記憶體暴增。把這些時間點記下來,對照 GCP 的監控事件。只要能把「記憶體曲線的拐點」跟「OOM killer 的報文」對上,你的排查就會快很多。

GCP帳號充值服務 2.2 檢查內核日誌:OOM Killer 的關鍵句

在 Linux VM 上,最直接的是看內核訊息,例如 /var/log/kern.logdmesg 相關輸出。你要找類似「Out of memory」或「Killed process」的段落。關鍵在於被殺的是哪個 PID、屬於哪個程式,還有當時整體可用記憶體狀態。

如果你是在容器環境,日誌可能會顯示某個容器內的主程式被殺。這時你要注意:容器被殺 ≠ 節點整體 OOM。容器可能先達到自己的 cgroup 記憶體上限。

2.3 在 GKE 裡看事件:容器層級的 OOM

如果是 GKE,你通常會看到 Pod 反覆重啟,並在描述或事件中看到類似 OOMKilled。這代表容器達到設定的 memory limit,被 kubelet 觸發殺死。此時「增加節點 Swap」不一定能直接阻止容器被 OOM,但它可能會緩解宿主機層的壓力,並讓記憶體回收更有空間。

在 GKE 上,要同時檢查:Pod 的 resources.limits.memoryrequests.memory、以及是否開啟了 Swap(不同方案/版本支援狀況不同)。如果容器被設得太緊,你增加 Swap 也可能只是延遲死亡,而不是消除限制。

第三章:排查路線圖:從指標到根因

排查 OOM 的順序建議是「先定量、後定性、最後定責」。你要先用數據確認記憶體到底是 緩慢長期增長 還是 瞬時爆發,再判斷是洩漏、快取不受控、還是單次任務處理太重。

3.1 記憶體曲線:緩慢上升 vs 突然尖峰

如果記憶體曲線是緩慢上升,通常偏向洩漏或累積性資料結構沒有釋放。若是突然尖峰,則可能是:批量任務、某次 query 回傳太大、反序列化過程佔用了大量臨時記憶體、或者壓縮/解壓/轉換流程在短時間內吃爆。

你可以把尖峰對應到應用的某些行為:例如每晚的匯入任務、每分鐘的報表生成、或某個新版本上線後的特定路徑。

GCP帳號充值服務 3.2 看可用記憶體與回收行為

GCP帳號充值服務 在 Linux 上,你要關心的不只是「總記憶體」,還包括:可用頁面、是否啟動了 swap、以及回收是否頻繁。你可以用 free -mvmstat/proc/meminfo 觀察 Swap 是否為 0、回收是否失控。

如果 Swap 為 0,代表你缺少緊急緩衝;當匿名頁或頁面緊張時,就更容易觸發 OOM Killer。這也是為什麼「增加 Swap」是很常見但常被忽略的防死機策略。

3.3 以 cgroup 為中心判斷容器限制

容器環境下,真正決定容器死亡的是 cgroup 記憶體。你要確認:容器是否有 memory limit、是否達到 limit 後立刻被 kill。你可以檢查 /sys/fs/cgroup 相關目錄(不同系統可能路徑略有差異)。

如果你發現容器的 limit 與實際 peak 不匹配,那根因就不是 Swap 的問題,而是 limits 設太小。這時你需要重新評估峰值需求,並調整 requests/limits,而不是只把希望放在 Swap。

第四章:解決策略一:增加 Swap 作為緩衝層

Swap 的角色不是讓你無限擴充記憶體,而是把「立刻死」變成「有時間慢慢活」。它可以吸收尖峰負載造成的瞬時記憶體壓力,並在某些場景讓應用完成任務或完成回收。

在 GCP 上,你可用的做法取決於你的部署型態。以下以 Compute Engine 的 VM 為例說明;若你是 GKE 或容器,需搭配實際支援情況。

4.1 為什麼沒有 Swap 特別容易 OOM

Swap 是把一部分不常使用的記憶體頁移到磁碟。當 RAM 壓力大時,系統可以用 swap 把內存釋放出來。若 swap 為 0,系統只有「丟棄可回收頁」與「直接殺進程」兩條路,當不可回收的匿名頁過多時,就很容易直接觸發 OOM。

4.2 建議的 Swap 容量與選擇原則

Swap 多不一定更好。過大的 Swap 可能造成磁碟 I/O 壓力,讓應用延遲飆升,甚至引發連鎖反應。較務實的做法是:以「避免 OOM killer」為目標,讓系統在少量時間內有空間完成任務。

常見做法是先設一個相對保守的值,例如 1GB、2GB 或 4GB,觀察記憶體尖峰是否被吸收。若你的工作負載有更長的記憶體緩衝需求,可以再逐步提高。具體容量最好基於過往 peak 與事件時間窗推估,而不是拍腦袋。

4.3 在 VM 上建立 Swap(概念與步驟)

建立 Swap 的基本流程通常是:準備一個 swap 檔案或 swap partition、設權限、格式化成 swap、啟用並設定持久化。

你可以考慮用 swap 檔案(swap file)因為操作彈性高。思路如下:選定檔案位置(例如根據你的磁碟配置選擇合適的路徑)、分配檔案大小、設權限為只有 root 可讀、用 mkswap 格式化、再用 swapon 啟用。最後要確保重開機後仍然存在,通常會在 /etc/fstab 設定。

此外還要調整 swappiness(例如 vm.swappiness),讓 swap 使用的積極度不至於過高。你希望它在「快沒 RAM 了」才比較願意動用,而不是平常就大規模換出。

4.4 若磁碟性能不足,Swap 可能變成新瓶頸

在雲端環境,磁碟 I/O 速度與延遲比本地 SSD 更變化。若你把 Swap 設得過大,系統可能會頻繁把頁面換入換出,導致整體吞吐下降。此時應用可能不是「不會 OOM」,而是「更慢、更抖」。

GCP帳號充值服務 因此 Swap 是防死機的保險,不是根治。你仍需要在應用層解決記憶體壓力的來源。

第五章:解決策略二:調整容器/程序的記憶體邊界

若你在容器環境,Swap 的效果常被容器限制削弱。更直接的做法是把「記憶體 limit」設對,並確保程式有合理的記憶體上限與釋放策略。

5.1 檢查 limits:是不是硬碰硬地設太低

你需要對照最近一段時間的 peak RSS(常駐集合大小)或容器記憶體用量。若 peak 已經幾乎貼著 limit,GC 或釋放延遲就會讓你在某些時段被 kill。

建議預留一定安全餘量,例如峰值的 20%~40%(具體看抖動程度)。但不要把 limit 設得太離譜,否則節點可能承擔過大壓力,導致其他 Pod 連鎖 OOM。

5.2 針對語言運行時:讓它知道自己有上限

很多程式在沒有明確上限時,會把記憶體用到你不希望它用的程度。例如 JVM 的最大堆、Go 的 GOGC、Node.js 的堆限制等。這些都應與容器的 limit 對齊。

如果你不做對齊,常見現象是:應用看似在工作,實際上把堆用到很高,GC 延遲上升,最後仍然撞上 cgroup limit 被殺死。你要做的是:讓運行時在更早的時間開始回收,避免在極限附近才被動回收。

5.3 限制快取與批處理:把峰值砍下來

OOM 很多時候不是「平均記憶體」問題,而是「峰值任務」問題。你可以從三個地方下手:快取策略、批量大小、以及中間資料的生成方式。

例如把一次性讀入改為流式處理;把批大小從 10 萬降到 1 萬;對不必要的緩存設 TTL;避免把超大資料結構一次性載入記憶體。

這些修改通常比「只加內存」更有效,因為它直接降低峰值,不會造成持續成本上升。

第六章:解決策略三:把根因修到位(不然 Swap 只是延命)

Swap 能救急,但真正能讓你不再反覆爆炸的是根因修復。下面列出常見根因與應對方向。

6.1 記憶體洩漏:長時間運行後越來越大

GCP帳號充值服務 如果你看到記憶體曲線一路上升,伴隨 GC 無法跟上或快取持續增長,可能是洩漏或引用沒有釋放。你需要做:壓測重現、記憶體快照/heap dump、以及追蹤大物件來源。

在排查階段,先把「哪個類型/哪個模組」吃最多找出來,再談修復。因為洩漏的修法非常依賴語言與框架。

6.2 緩存不受控:資料量增長導致快取膨脹

很多服務在早期資料量小時不會出事,但當資料累積後,快取突然變成記憶體黑洞。你要確認快取是否有上限(size cap)、是否有 TTL、是否有 eviction 策略。

如果沒有,就補上。若快取需要較大的容量,也要確保它建立在「可預期」的資料量之上,而不是不設限。

6.3 臨時資料過大:一次性聚合或序列化

OOM 常常發生在「看似不該很大」的地方,例如生成報表、合併結果集、或把查詢結果一次性轉成大物件。這些操作在短時間內建立大量臨時資料,導致峰值超過 limit。

解法是分段處理、流式轉換,或把聚合改成在資料庫端做得更節省。還有一個容易忽略的點是:序列化/反序列化可能同時佔用多份中間表示形式,你要把它們的峰值算進去。

6.4 外部依賴延遲造成堆積:不是快取,是任務堆在那裡

當外部 API、資料庫或訊息隊列延遲變高,任務會在應用端排隊。排隊本身就是記憶體消耗。你要確認:在崩潰前是否出現下游延遲上升或重試風暴。

此時要做的不是立刻加記憶體,而是調整併發、超時、重試退避、以及背壓(backpressure)策略。

第七章:一個可落地的排查流程(你照著做就能收斂)

GCP帳號充值服務 把前面的內容收斂成一個流程,讓你在第一次遇到 OOM 時不會亂猜。

7.1 收集資料(先把證據集起來)

列出事件時間、被殺的進程/容器、節點與 Pod 名稱。同步抓取:記憶體用量曲線、CPU 曲線、Swap 狀態、以及相關日誌。

如果你能找到 OOM Killer 的訊息,把它的時間與節點記憶體狀態寫在同一張時間軸上。

7.2 判斷屬性:節點 OOM 還是容器 OOM

如果是節點 OOM,Swap 設定與整機記憶體策略就更重要。若是容器 OOM,你要優先檢查 memory limit 與運行時記憶體上限對齊。

這一步是分流的核心:不同分流的策略完全不一樣。

7.3 確認壓力型態:洩漏、膨脹快取、或尖峰任務

看曲線:上升是否持續,還是短時間急劇上升。把峰值對應到應用行為,鎖定候選模組。

7.4 用 Swap 與限流/調參做「止血」

在你還沒找到根因前,用 Swap 與運行時/併發/批次等手段把峰值壓下來。這樣至少能避免服務在排查過程中反覆宕機,讓你有時間做深挖。

止血的優先順序可以是:先調小峰值(限流、批次、並發),再調運行時上限(GC/heap),最後才是 Swap 作緩衝。

7.5 找根因並驗證:確保修完後曲線不再回去

修完後要重新跑類似壓測或用同樣的流量回放。你要看兩件事:最大峰值是否下降、以及記憶體是否不再持續上升。

只有曲線穩了,你才能真正說「解決」而不是「暫時撐住」。

第八章:如何避免「加 Swap 但仍然 OOM」的常見誤區

很多人加了 Swap 之後依然看到 OOM,常見原因如下。

8.1 Swap 太小或被快速耗盡

如果你的尖峰遠大於 Swap 容量,Swap 只能多撐一點點時間。你需要從過往峰值估算要撐多長,而不是一開始就設太小。

8.2 容器 limit 先把你殺了

容器達到 memory limit,可能立刻被 kill;Swap 的緩衝並不能越過 cgroup 的硬限制。此時要優先調整 memory limit 或減少容器內的峰值。

8.3 你把 swappiness 調得太激進

如果讓系統太積極換出頁面,可能導致頻繁 I/O,使應用延遲上升,吞吐下降,進而在上層形成堆積,反而更容易觸發資源耗盡。Swap 是防死機,不是追求高換出率。

8.4 你只看「有沒有 Swap」,沒看「實際 swap usage」

你要看事件發生時 Swap 是否真的被使用,以及使用量是否持續上升。如果 Swap 幾乎不動,代表 OOM 可能不是單純 RAM 緊張,可能是不可回收頁、運行時配置、或應用的結構性問題。

第九章:把策略落在日常運維:監控與預警

解決 OOM 後,真正重要的是避免再次發生。你需要把「記憶體風險」提前變成可觀測的訊號。

9.1 設計預警:靠近 limit 的行為要提早告警

在 VM 上可以用可用記憶體、交換使用量、以及回收行為作訊號。在容器上則用容器記憶體用量相對於 limit 的比例。你要避免只在 OOM 已經發生後才知道。

9.2 記錄每次 OOM 的五個欄位

建議你的 runbook 直接要求填寫:時間、節點/Pod、峰值記憶體曲線、Swap 使用量、以及最後一次成功處理的請求/批次類型。資料越結構化,你越能快速定位模式。

9.3 用演練把「加 Swap」變成流程,而不是臨時救火

Swap 調整最好有標準化的做法:容量範圍、swappiness 的合理區間、啟用後的觀察指標、以及回滾方案。當你在凌晨收到告警時,你不應該還在思考 Swap 的參數該怎麼設。

第十章:結論——以 Swap 防死機,但以根因終結循環

GCP 上的 OOM 崩潰,常常不是一句「記憶體不夠」就能交代。真正要做的是:把觸發點對齊到節點或容器層級、確認是洩漏/快取膨脹/尖峰任務/下游延遲堆積中的哪一類,然後用止血策略讓服務活下來。

增加 Swap 是很有效的防死機措施:它能讓系統在極端壓力下多一點時間,讓回收或任務完成有機會發生。但它永遠不是根治。當你能把 limits 設對、把運行時上限對齊、把峰值任務拆分或限流,並針對洩漏與快取做修復,記憶體曲線才會真正回到可預期的範圍。

如果你打算從今天開始改進,我建議你把下一次 OOM 當作一次「資料收斂」任務:先收集證據,再分流定位,再止血(包含 Swap),最後用修復驗證。這樣你會發現 OOM 不再是恐懼,而是一個可以被系統化處理的問題。

Telegram售前客服
客服ID
@cloudcup
联系
Telegram售后客服
客服ID
@yanhuacloud
联系