首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

解決 Java "Cannot allocate memory" 啟動失敗:原理與兩種修復方案

     編輯:Java 相關知識

現象重現

在記憶體受限的伺服器(如 1GB RAM VPS)執行 java -version 即報錯:

Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00007ff55c5ea000, 4096, 0) failed; error='Cannot allocate memory' (errno=12)
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 4096 bytes for committing reserved memory.

根因分析:fork/exec 機制導致虛擬記憶體瞬間翻倍

JVM 在啟動子進程(如 ProcessBuilder、JNI 呼叫系統指令)時,會先 fork() 複製父進程記憶體映射,再 exec() 載入新程式。Linux 預設採用 Strict Overcommit 策略:fork() 瞬間需要為子進程預留與父進程相同大小的虛擬記憶體,即使隨後 exec() 會釋放大部分頁面,峰值提交量仍可能超過物理記憶體+Swap 上限,導致 mmap 失敗。

方案一:啟用 Kernel Overcommit(推薦,風險可控)

修改 /proc/sys/vm/overcommit_memory 為 1(Always Overcommit),核心不再檢查可用記憶體直接允許分配。

臨時生效(重啟失效)

echo 1 > /proc/sys/vm/overcommit_memory

永久生效

# /etc/sysctl.conf
vm.overcommit_memory = 1
# 執行 sysctl -p 或重啟生效

副作用:若惡意程式大量 malloc 卻不使用,可能觸發 OOM Killer 殺死隨機進程。生產環境建議同時配置 vm.overcommit_ratio 並監控記憶體水位。

方案二:替換 fork/exec 為 posix_spawn(根治但需 JNI)

JDK 9+ 已在 ProcessBuilder 內部嘗試使用 posix_spawn 避免 fork 記憶體翻倍。若受限於舊版 JDK,可採用:

  • 升級至 JDK 11/17 LTS 版本;
  • 或引入 jni-posix-spawn 等第三方庫,透過 JNI 繞過 fork;
  • 容器化部署時設定 --memory-swappiness=0 並給予足夠 --memory 配額。

快速驗證清單

  1. free -h 確認物理記憶體與 Swap 可用量;
  2. cat /proc/sys/vm/overcommit_memory 檢查當前策略(0=heuristic, 1=always, 2=strict);
  3. 調整後再次執行 java -version 應無錯誤輸出;
  4. 啟動實際應用並觀察 dmesg | grep -i oom 確無 OOM Killer 記錄。

參考資源

  • Bryan Marty - Forking the JVM
  • Linux Kernel 文檔:Documentation/vm/overcommit-accounting
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved