首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 啟動報「Out of memory」但內存充足?vm.overcommit_memory 內核參數陷阱

     編輯:MySQL 資料庫相關知識

現象:128GB 內存、佔用極低,MySQL 啟動卻報「Cannot allocate memory」

2023-01-01 00:00:00 [ERROR] InnoDB: Cannot allocate memory for the buffer pool

free -h 顯示可用 100GB+,top 內存壓力極小。配置 innodb_buffer_pool_size=96G,理應足夠。

排查定位:vm.overcommit_memory = 2 限制虛擬記憶體提交

# 對比兩台相同硬體配置的伺服器
# 正常啟動機器
sysctl vm.overcommit_memory
vm.overcommit_memory = 0

# 故障機器
sysctl vm.overcommit_memory
vm.overcommit_memory = 2

原理深度解析

vm.overcommit_memory 控制核心對記憶體超額提交的策略:

值策略適用場景
0 (預設)啟發式:核心估算可用記憶體,允許合理超額通用生產環境
1總是允許超額,直到物理+Swap 用盡科學計算、稀疏矩陣、明確知道不會真用滿
2**嚴格模式**:總提交限制 = Swap + RAM × overcommit_ratio%(預設 50%)安全敏感、防止 OOM Killer、嚴格容量規劃

故障機器 vm.overcommit_memory=2、overcommit_ratio=50:

CommitLimit = Swap + RAM * 50%
            = 4GB + 128GB * 50%
            = 68GB

MySQL 啟動時向核心申請 96GB 虛擬記憶體(malloc buffer pool),超過 68GB 限制 → 核心拒絕 → MySQL 報 OOM。

驗證 CommitLimit

cat /proc/meminfo | grep CommitLimit
CommitLimit: 70144396 kB   # ≈ 68GB

解決:恢復預設策略

# 臨時生效
echo 0 > /proc/sys/vm/overcommit_memory
# 或
sysctl -w vm.overcommit_memory=0

# 永久生效
echo "vm.overcommit_memory = 0" >> /etc/sysctl.conf
sysctl -p

修改後 MySQL 即可正常啟動,分配 96GB buffer pool 成功。
修改後啟動成功

根因回溯:歷史業務遺留配置

該伺服器先前運行 **Greenplum**(MPP 數據倉庫),其部署文檔要求設定 vm.overcommit_memory=2 以防止段節點 OOM。遷移至 MySQL 時未重置內核參數,導致策略不匹配。

教訓與最佳實踐

  1. 接手舊機器必須重裝系統或全量審查內核參數(sysctl -a 對比基準模板)。
  2. MySQL/InnoDB 建議 vm.overcommit_memory=0 或 1,嚴格模式 2 會人為限制大內存分配。
  3. 部署自動化腳本(Ansible/Terraform)應包含內核參數基線,確保環境一致性。
  4. 監控 CommitLimit 與 Committed_AS**,預警虛擬記憶體提交逼近上限。

一個內核參數差異,導致百萬級內存資源無法使用。運維核心功夫:**懂業務特性、懂核心策略、懂歷史遺留**,三者缺一不可。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved