oom_killer 默認配置下,當沒有內存可以用而又要用到內存時,Linux內核的oom_killer(out of memory killer)會掃描一遍占用內存最多的程序(可能有多個),並把它們結束掉。
這種掃描其實代價還是挺大的,可以選擇讓oom_killer不要掃描出用內存最多的進程,只是解決掉申請內存的那些進程: sysctl -w vm.oom_kill_allocating_task = 1 使用這樣的設置,oom_killer不會去花時間尋找占內存最多的進程殺掉,大內存程序就有一定機會幸免。但是在內存 用完的那一瞬間,誰去申請或者使用一片空白的內存,誰就會悲劇,而且可能是幾個進程一起被殺掉,充滿了不可預測性(比如,Xorg被殺掉,於是許多程序連 帶就掛掉了,再比如後台的mysqld被殺掉也會帶來許多不方便),而且也沒有避免pdflush在最後關頭讓硬盤燈狂閃的情況。 總之,oom_killer很不和諧,最好不要讓它出場。
在這一點上,openSolaris似乎做的就比較好,從外表上看,在內存不夠的時候,系統不會去主動殺掉正在運行的程序,而是拒絕運行新的程序,並且運行中的程序如果申請內存的話就會被暫停,直至有內存可以給它的時候才繼續運行。 overcommit 那麼系統為什麼不能提前檢測到內存用完呢,malloc是有可能返回NULL的啊?現在的操作系統中,允許過分地申請內存,如果只是申請內存而沒有實際使用的話,可以申請到比實際內存大許多的空間(比如用malloc申請內存,while(1) malloc(x);這樣的程序都可以運行好長時間),只有一旦開始用(比如用memset去填),才會計入真正的內存使用,這時候如果內存真的不夠了,那麼oom_killer就上場了。 目前的Linux提供了一些選項用來調整這種內存策略 :-)
默認情況下,vm.overcommit_memory = 0,這時候可以申請到比較多的內存,但是仍然會在一定的時候申請失敗。
還有更寬松一些的,如果 vm.overcommit_memory = 1,所有的malloc都會無條件成功 相當可怕的世界。
最後一種選擇就是這個了: sysctl -w vm.overcommit_memory = 2 這時候,對申請內存總數有嚴格的限制,malloc會在超過限制的時候返回NULL,應用程序可以適當處理這種情況,而oom_killer再也不會蹦出來了,pdflush也不會讓硬盤轉得系統沒響應,如果一個程序不能適當處理這種情況,就立即掛掉,干淨利落。
但是這也有壞處,這時候參數vm.overcommit_ratio也會起作用,默認是50,意思是只能分配到實際物理內存的50%。如果沒有交換區的話,overcommit_ratio設置得小就會很悲劇,幾乎什麼都做不了。 那把它設置成100,事情就非常和諧了?沒有這樣簡單,這裡的限制是申請內存總數的限制,如果申請了卻沒有實際用到的話,也是計入總數的。這樣的話,實際內存沒有用完,程序也很有可能申請不到內存,有一些內存就被浪費了。 雖然overcommit_ratio可以被設置成大於100的數,但是到底設置成多少確是個棘手的問題,設置大了,就和沒有限制一樣,內存用完時硬盤會狂轉,系統會失去響應一段時間,oom_killer有可能會上場,設置小了,有可能幾百兆的內存被白白浪費了 檢查內存信息可以看到:
% cat /proc/meminfo
MemTotal: 2064616 kB
MemFree: 1556672 kB
….
CommitLimit: 2064616 kB
Committed_AS: 769068 kB
….
其中Committed_AS是程序申請的內存總和,不能超過CommitLimit。
很明顯地看到Committed_AS+MemFree比MemTotal大,看起來把CommitLimit設置成Committed_AS+MemFree比較合適。