Cannot allocate memory 的分析及解決方法
問題
業務方使用Python虛擬的子進程和主進程共享內存,主進程啟動后,啟動子進程時報錯"Cannot allocate memory"
問題分析
可能的原因:
- 系統的物理RAM或交換空間不足
- 進程在啟用CompressedOops的情況下運行,Java堆可能會阻止本機堆的增長
可能的解決方案:
- 減少系統內存負載
- 增加物理內存或交換空間
- 檢查交換備份存儲是否已滿
- 減小Java堆大小(-Xmx/-Xms)
- 減少Java線程數
- 減少Java線程堆棧大小(-Xss)
- 使用-XX:ReservedCodeCacheSize設置更大的代碼緩存=
- JVM運行的是無標度的壓縮Oops模式,其中Java堆是
- 放在第一個4GB地址空間。Java堆基址是
- 本機堆增長的最大限制。請使用-XX:HeapBaseMinAddress
- 設置Java堆基並將Java堆放置在4GB虛擬地址之上
咋一看是懷疑內存不足,但從監控來看,內存還有很多富裕
進程
看到提供的可能的解決方案中有需要減少java線程數,聯想到服務器的進程數是不是滿了,首先查看服務器最大進程數 sysctl kernel.pid_max
接着一查看進程數ps -eLf | wc –l,16149遠遠還沒到32768啊,那肯定也不是進程數滿了的原因,排除。
內核參數overcommit_memory
Linux下有個內核參數overcommit_memory,是內存分配策略,程序在啟動的時候會先去申請內存,盡管不一定都會用的到那么多。
overcommit_memory此參數決定是否接受超大內存請求的條件。這個參數有三個可能的值:
- 0 — 默認設置。內核執行啟發式內存過量使用處理,方法是估算可用內存量,並拒絕明顯無效的請求。遺憾的是因為內存是使用啟發式而非准確算法計算進行部署,這個設置有時可能會造成系統中的可用內存超載。
- 1 — 內核執行無內存過量使用處理。使用這個設置會增大內存超載的可能性,但也可以增強大量使用內存任務的性能。
- 2 — 內存拒絕等於或者大於總可用 swap 大小以及overcommit_ratio指定的物理RAM比例的內存請求。如果您希望減小內存過度使用的風險,這個設置就是最好的。
目前的內存申請和可用情況cat /proc/meminfo | grep Commit - CommitLimit 表示系統可申請的總內存
- Committed_AS為當前已經申請的內存
理解下什么是Overcommit和OOM:
Linux對大部分申請內存的請求都回復"yes",以便能跑更多更大的程序。因為申請內存后,並不會馬上使用內存。這種技術叫做Overcommit。當linux發現內存不足時,會發生OOM killer(OOM=out-of-memory)。它會選擇殺死一些進程(用戶態進程,不是內核線程),以便釋放內存。
當oom-killer發生時,linux會選擇殺死哪些進程?選擇進程的函數是oom_badness函數(在mm/oom_kill.c中),該函數會計算每個進程的點數(0~1000)。點數越高,這個進程越有可能被殺死。每個進程的點數跟oom_score_adj有關,而且oom_score_adj可以被設置(-1000最低,1000最高)。
解決方法
有三種方式修改內核參數,但要有root權限:
- 編輯/etc/sysctl.conf ,改vm.overcommit_memory=1,然后sysctl -p使配置文件生效
- sysctl vm.overcommit_memory=1
- echo 1 > /proc/sys/vm/overcommit_memory,然后sysctl –p永久生效
