錯誤日誌出現 mysqld-nt: Out of memory (Needed 1677720 bytes),網站變慢甚至服務不可用。伺服器物理記憶體 32GB,但運行 32 位作業系統與 32 位 MySQL。
32 位進程最大可定址 4GB 虛擬記憶體,Linux 核心預設分配 3GB 給用戶空間,1GB 給核心空間。即便物理記憶體 32GB,單一 MySQL 進程也**無法使用超過 3GB** 記憶體。若配置參數總和超過此限制,即觸發 OOM。
MySQL 總記憶體佔用估算公式:
總記憶體 ≈ key_buffer_size + (read_buffer_size + sort_buffer_size + read_rnd_buffer_size + join_buffer_size) * max_connections + innodb_buffer_pool_size + innodb_log_buffer_size + innodb_additional_mem_pool_size + max_heap_table_size / tmp_table_size (較大者) + thread_stack * max_connections + 其他固定開銷
核心原則: 此總和必須 小於 3GB (約 3,000MB)。
SHOW VARIABLES LIKE '%buffer%'; SHOW VARIABLES LIKE '%heap%'; SHOW VARIABLES LIKE '%tmp_table%'; SHOW VARIABLES LIKE 'max_connections'; SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
| 參數 | 原值 (問題值) | 調整後 | 說明 |
|---|---|---|---|
| key_buffer_size | 512M | 128M | MyISAM 索引緩衝,建議 ≤ 實體記憶體 25% |
| max_heap_table_size | 512M | 128M | 內存表最大值,與 tmp_table_size 配合 |
| tmp_table_size | 512M | 128M | 內部臨時表最大值,超過轉磁碟 |
| innodb_buffer_pool_size | 1512M | 1000M | InnoDB 核心緩衝池,此處調整為 1G |
| sort_buffer_size | 2GB | 2M | **每連線**分配,設 2GB 極其危險 |
| read_buffer_size | 2GB | 2M | **每連線**分配,同理極其危險 |
| read_rnd_buffer_size | 4M | 4M | 保持預設 |
| join_buffer_size | 默認 | 2M | **每連線**分配,無索引 Join 時使用 |
| max_connections | 默認 151 | 500 | 根據業務調整,影響總記憶體上限 |
修改 my.cnf 後重啟 MySQL,持續監控 5+ 小時,錯誤日誌不再出現 Out of memory,服務穩定運行。
[mysqld] # 全局緩衝 key_buffer_size = 128M innodb_buffer_pool_size = 1G innodb_log_buffer_size = 64M max_heap_table_size = 128M tmp_table_size = 128M # 每連線緩衝 (謹慎設定,乘以 max_connections) sort_buffer_size = 2M read_buffer_size = 2M read_rnd_buffer_size = 4M join_buffer_size = 2M thread_stack = 256K # 連線控制 max_connections = 500 thread_cache_size = 50 # 其他 query_cache_size = 0 # 高並發建議關閉 QC query_cache_type = 0 table_open_cache = 2048 table_definition_cache = 2048
若 PHP 報錯 Fatal error: Out of memory (allocated 262144) (tried to allocate 19456 bytes),同屬 32 位進程記憶體耗盡。解決:修改 php.ini 提高 memory_limit (如 128M 或 256M),並重啟 Apache/PHP-FPM。但根本上應排查 PHP 程式碼記憶體洩漏或單腳本過度消耗。
sort_buffer_size、read_buffer_size、join_buffer_size 乘以 max_connections 才是真實佔用。innodb_buffer_pool_size 發揮 SSD/大記憶體優勢。