釘釘群收到告警爆袍,redis服務(wù)兩個(gè)掛了艇肴。登錄服務(wù)器通過(guò)dmesg命令查看進(jìn)程掛掉原因哄酝,看到以下日志
[21367253.038320] Node 0 DMA free:15908kB min:8kB low:8kB high:12kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes
[21367253.046752] lowmem_reserve[]: 0 2825 96503 96503
[21367253.048506] Node 0 DMA32 free:376572kB min:1976kB low:2468kB high:2964kB active_anon:2441228kB inactive_anon:16kB active_file:12kB inactive_file:16kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3129212kB managed:2893660kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:16kB slab_reclaimable:49568kB slab_unreclaimable:2944kB kernel_stack:448kB pagetables:16104kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:8 all_unreclaimable? no
[21367253.057509] lowmem_reserve[]: 0 0 93677 93677
[21367253.059225] Node 0 Normal free:85808kB min:65592kB low:81988kB high:98388kB active_anon:94857072kB inactive_anon:256kB active_file:3492kB inactive_file:3120kB unevictable:0kB isolated(anon):0kB isolated(file):128kB present:97517568kB managed:95925820kB mlocked:0kB dirty:0kB writeback:0kB mapped:996kB shmem:620kB slab_reclaimable:72616kB slab_unreclaimable:35820kB kernel_stack:4752kB pagetables:227860kB unstable:0kB bounce:0kB free_pcp:2560kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:9970 all_unreclaimable? yes
[21367253.069788] lowmem_reserve[]: 0 0 0 0
[21367253.071491] Node 0 DMA: 1*4kB (U) 0*8kB 0*16kB 1*32kB (U) 2*64kB (U) 1*128kB (U) 1*256kB (U) 0*512kB 1*1024kB (U) 1*2048kB (M) 3*4096kB (M) = 15908kB
[21367253.075622] Node 0 DMA32: 2355*4kB (UEM) 2103*8kB (UEM) 584*16kB (UEM) 293*32kB (UEM) 131*64kB (UEM) 5*128kB (EM) 58*256kB (UM) 275*512kB (UM) 163*1024kB (M) 0*2048kB 0*4096kB = 376548kB
[21367253.080198] Node 0 Normal: 21012*4kB (UEM) 251*8kB (UEM) 21*16kB (EM) 2*32kB (EM) 1*64kB (M) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 86520kB
[21367253.084547] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
[21367253.086812] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
[21367253.089058] 2129 total pagecache pages
[21367253.090883] 0 pages in swap cache
[21367253.092648] Swap cache stats: add 0, delete 0, find 0/0
[21367253.094588] Free swap = 0kB
[21367253.096303] Total swap = 0kB
[21367253.098010] 25165693 pages RAM
[21367253.099735] 0 pages HighMem/MovableOnly
[21367253.101522] 456846 pages reserved
[21367253.103259] [ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
[21367253.105522] [ 3086] 0 3086 20024 87 45 0 0 systemd-journal
[21367253.107824] [ 5969] 0 5969 6718 217 18 0 0 systemd-logind
[21367253.110105] [ 5970] 81 5970 14564 179 31 0 -900 dbus-daemon
[21367253.112372] [ 5983] 0 5983 615231 10802 91 0 0 CmsGoAgent.linu
[21367253.114683] [ 6054] 0 6054 27523 33 11 0 0 agetty
[21367253.116926] [ 6058] 0 6058 27523 33 11 0 0 agetty
[21367253.119135] [ 6316] 0 6316 26839 498 51 0 0 dhclient
[21367253.121366] [ 7035] 0 7035 138962 1919 39 0 0 ops-updater
[21367253.123756] [ 7079] 0 7079 589598 6289 85 0 0 falcon-agent
[21367253.126011] [13594] 1000 13594 11667269 6644047 19394 0 0 redis-server
[21367253.128270] [13599] 1000 13599 8243013 6664731 15518 0 0 redis-server
[21367253.130502] [15685] 1000 15685 6917957 5449843 13398 0 0 redis-server
[21367253.132724] [15693] 1000 15693 5857093 5411665 11080 0 0 redis-server
[21367253.134943] [32218] 1000 32218 127813 52828 152 0 0 redis-server
[21367253.137165] [32223] 1000 32223 113477 56705 139 0 0 redis-server
[21367253.139349] [32736] 1000 32736 28295 67 13 0 0 sh
[21367253.141429] [20078] 0 20078 78343 3993 104 0 0 salt-minion
[21367253.143574] [20083] 0 20083 237123 11662 163 0 0 salt-minion
[21367253.145663] [20087] 0 20087 103223 6598 113 0 0 salt-minion
[21367253.147739] [14046] 0 14046 10494 216 13 0 0 aliyun-service
[21367253.149802] [ 3366] 0 3366 109273 676 28 0 0 AliHips
[21367253.151773] [ 9827] 0 9827 6614 359 18 0 0 AliYunDunUpdate
[21367253.153774] [ 9944] 0 9944 32536 1953 59 0 0 AliYunDun
[21367253.155691] [ 340] 0 340 28230 258 57 0 -1000 sshd
[21367253.157612] [ 483] 28 483 148240 135 43 0 0 nscd
[21367253.159441] [ 557] 0 557 13882 112 26 0 -1000 auditd
[21367253.161233] [ 691] 998 691 24120 95 18 0 0 chronyd
[21367253.163013] [ 729] 0 729 31573 157 18 0 0 crond
[21367253.164794] [ 814] 999 814 153061 2128 63 0 0 polkitd
[21367253.166505] [28544] 0 28544 11152 105 23 0 -1000 systemd-udevd
[21367253.168272] [28629] 0 28629 160279 185 142 0 0 rsyslogd
[21367253.169980] Out of memory: Kill process 13599 (redis-server) score 270 or sacrifice child
[21367253.171663] Killed process 13599 (redis-server) total-vm:32972052kB, anon-rss:26658828kB, file-rss:88kB, shmem-rss:0kB
日志內(nèi)容顯示 Out of memory: Kill process 13599 (redis-server)
麦向,所以是由于內(nèi)存不足瓢棒,被系統(tǒng)給結(jié)束了進(jìn)程浴韭。
原因分析
1). redis-server進(jìn)程觸發(fā)了oom killer,既redis要申請(qǐng)的內(nèi)存大于了系統(tǒng)可用的物理內(nèi)存大小脯宿。/proc/sys/vm/min_free_kbytes 參數(shù)來(lái)控制念颈,當(dāng)系統(tǒng)可用內(nèi)存(不包含buffer和cache)小于這個(gè)值的時(shí)候,系統(tǒng)會(huì)啟動(dòng)內(nèi)核線程kswapd來(lái)對(duì)內(nèi)存進(jìn)行回收连霉。而還是觸發(fā)了oom killer榴芳,則表明內(nèi)存真的不夠用了或者在內(nèi)存回收前或者回收中直接觸發(fā)了oom killer。
2). 如下的輸出表明了申請(qǐng)了3次內(nèi)存都沒(méi)有成功
[21367253.038320] Node 0 DMA free:15908kB min:8kB low:8kB high:12kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes
[21367253.046752] lowmem_reserve[]: 0 2825 96503 96503
[21367253.048506] Node 0 DMA32 free:376572kB min:1976kB low:2468kB high:2964kB active_anon:2441228kB inactive_anon:16kB active_file:12kB inactive_file:16kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3129212kB managed:2893660kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:16kB slab_reclaimable:49568kB slab_unreclaimable:2944kB kernel_stack:448kB pagetables:16104kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:8 all_unreclaimable? no
[21367253.057509] lowmem_reserve[]: 0 0 93677 93677
[21367253.059225] Node 0 Normal free:85808kB min:65592kB low:81988kB high:98388kB active_anon:94857072kB inactive_anon:256kB active_file:3492kB inactive_file:3120kB unevictable:0kB isolated(anon):0kB isolated(file):128kB present:97517568kB managed:95925820kB mlocked:0kB dirty:0kB writeback:0kB mapped:996kB shmem:620kB slab_reclaimable:72616kB slab_unreclaimable:35820kB kernel_stack:4752kB pagetables:227860kB unstable:0kB bounce:0kB free_pcp:2560kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:9970 all_unreclaimable? yes
[21367253.069788] lowmem_reserve[]: 0 0 0 0
[21367253.071491] Node 0 DMA: 1*4kB (U) 0*8kB 0*16kB 1*32kB (U) 2*64kB (U) 1*128kB (U) 1*256kB (U) 0*512kB 1*1024kB (U) 1*2048kB (M) 3*4096kB (M) = 15908kB
[21367253.075622] Node 0 DMA32: 2355*4kB (UEM) 2103*8kB (UEM) 584*16kB (UEM) 293*32kB (UEM) 131*64kB (UEM) 5*128kB (EM) 58*256kB (UM) 275*512kB (UM) 163*1024kB (M) 0*2048kB 0*4096kB = 376548kB
[21367253.080198] Node 0 Normal: 21012*4kB (UEM) 251*8kB (UEM) 21*16kB (EM) 2*32kB (EM) 1*64kB (M) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 86520kB
[21367253.084547] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
[21367253.086812] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
[21367253.089058] 2129 total pagecache pages
[21367253.090883] 0 pages in swap cache
[21367253.092648] Swap cache stats: add 0, delete 0, find 0/0
[21367253.094588] Free swap = 0kB
[21367253.096303] Total swap = 0kB
[21367253.098010] 25165693 pages RAM
[21367253.099735] 0 pages HighMem/MovableOnly
[21367253.101522] 456846 pages reserved
各個(gè)zone的情況如何跺撼?
[21367253.038320] Node 0 DMA free:15908kB min:8kB low:8kB high:12kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes
lowmem_reserve[]: 0 2825 96503 96503
[21367253.048506] Node 0 DMA32 free:376572kB min:1976kB low:2468kB high:2964kB active_anon:2441228kB inactive_anon:16kB active_file:12kB inactive_file:16kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3129212kB managed:2893660kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:16kB slab_reclaimable:49568kB slab_unreclaimable:2944kB kernel_stack:448kB pagetables:16104kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:8 all_unreclaimable? no
lowmem_reserve[]: 0 0 93677 93677
[21367253.059225] Node 0 Normal free:85808kB min:65592kB low:81988kB high:98388kB active_anon:94857072kB inactive_anon:256kB active_file:3492kB inactive_file:3120kB unevictable:0kB isolated(anon):0kB isolated(file):128kB present:97517568kB managed:95925820kB mlocked:0kB dirty:0kB writeback:0kB mapped:996kB shmem:620kB slab_reclaimable:72616kB slab_unreclaimable:35820kB kernel_stack:4752kB pagetables:227860kB unstable:0kB bounce:0kB free_pcp:2560kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:9970 all_unreclaimable? yes
lowmem_reserve[]: 0 0 0 0
可以看到Normal還有85808KB窟感,DMA32還有376572 KB,DMA還有15908KB歉井,
各個(gè)zone的free都大于min,分配是有鏈條的柿祈,Normal不夠了,會(huì)從DMA32以及DMA去請(qǐng)求分配哩至,所以為什么分配失敗了呢躏嚎?
雖然說(shuō)分配內(nèi)存會(huì)按照Normal、DMA32菩貌、DMA的順序去分配卢佣,但是低端內(nèi)存相對(duì)來(lái)說(shuō)更寶貴些,為了防止低端內(nèi)存被高端內(nèi)存用完箭阶,珠漂,linux設(shè)計(jì)了保護(hù)機(jī)制晚缩,也就是lowmen_reserve,從上面的日志看媳危,他們的值是這樣的:
- DMA(index=0): lowmem_reserve[]:0 2825 96503 96503
- DMA32(index=1)owmem_reserve[]: 0 0 93677 93677
- DMA32(index=2)lowmem_reserve[]: 0 0 0 0
lowmen_reserve的值是一個(gè)數(shù)組荞彼,當(dāng)Normal(index=2)像DMA32申請(qǐng)內(nèi)存的時(shí)候,需要滿足條件:
DMA32 high+lowmem_reserve[2] < free待笑,才能申請(qǐng)鸣皂,來(lái)算下:
Normal:從自己這里申請(qǐng),free(85808kB) > min(65592kB )暮蹂,可以申請(qǐng)寞缝,但是只能申請(qǐng) 85808kB-65592kB = 20216kb,不夠申請(qǐng)的內(nèi)存仰泻,所以申請(qǐng)失敗了(watermark[min]以下的內(nèi)存屬于系統(tǒng)的自留內(nèi)存荆陆,用以滿足特殊使用,所以不會(huì)給用戶態(tài)的普通申請(qǐng)來(lái)用)
Normal轉(zhuǎn)到DMA32申請(qǐng):high(2964kB) + lowmem_reserve2*4 > DMA32 Free(376572kB),不允許申請(qǐng)
Normal轉(zhuǎn)到DMA申請(qǐng):high(12kB) + lowmem_reserve2*4 > DMA Free(15908kB),不允許申請(qǐng),所以….最終失敗了
min_free_kbytes
這里屬于擴(kuò)展知識(shí)了集侯,和分析oom問(wèn)題不大被啼。我們知道了每個(gè)區(qū)都有min、low棠枉、high浓体,那他們是怎么計(jì)算出來(lái)的,就是根據(jù)min_free_kbytes計(jì)算出來(lái)的辈讶,他本身在系統(tǒng)初始化的時(shí)候計(jì)算命浴,最小128K,最大64M
- watermark[min] = min_free_kbytes換算為page單位即可贱除,假設(shè)為min_free_pages生闲。(因?yàn)槭敲總€(gè)zone各有一套watermark參數(shù),實(shí)際計(jì)算效果是根據(jù)各個(gè)zone大小所占內(nèi)存總大小的比例月幌,而算出來(lái)的per zone min_free_pages)
- watermark[low] = watermark[min] * 5 / 4
- watermark[high] = watermark[min] * 3 / 2
min 和 low的區(qū)別
- min下的內(nèi)存是保留給內(nèi)核使用的碍讯;當(dāng)?shù)竭_(dá)min,會(huì)觸發(fā)內(nèi)存的direct reclaim
- low水位比min高一些飞醉,當(dāng)內(nèi)存可用量小于low的時(shí)候冲茸,會(huì)觸發(fā) kswapd回收內(nèi)存屯阀,當(dāng)kswapd慢慢的將內(nèi)存 回收到high水位缅帘,就開(kāi)始繼續(xù)睡眠
3)被干掉進(jìn)程信息
[21367253.169980] Out of memory: Kill process 13599 (redis-server) score 270 or sacrifice child
[21367253.171663] Killed process 13599 (redis-server) total-vm:32972052kB, anon-rss:26658828kB, file-rss:88kB, shmem-rss:0kB
被kill的進(jìn)程pid是13599.進(jìn)程所占用的內(nèi)存頁(yè)是 6664731,換算內(nèi)存大概占用 換算為內(nèi)存占用量是6664731*4096 = 26GB和 anon-rss:26658828kB顯示占用的內(nèi)存差不多难衰。
[21367253.103259] [ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
[21367253.105522] [ 3086] 0 3086 20024 87 45 0 0 systemd-journal
[21367253.107824] [ 5969] 0 5969 6718 217 18 0 0 systemd-logind
[21367253.110105] [ 5970] 81 5970 14564 179 31 0 -900 dbus-daemon
[21367253.112372] [ 5983] 0 5983 615231
進(jìn)程輸出的含義是:
- pid進(jìn)程ID钦无。
- uid用戶ID。
- tgid線程組ID盖袭。
- total_vm虛擬內(nèi)存使用(單位為4 kB內(nèi)存頁(yè))
- rss 常駐內(nèi)存使用(單位4 kB內(nèi)存頁(yè))
- nr_ptes頁(yè)表項(xiàng)
- swapents交換條目
- oom_score_adj通常為0;較低的數(shù)字表示當(dāng)調(diào)用OOM殺手時(shí)失暂,進(jìn)程將不太可能死亡彼宠。 值越高越被系統(tǒng)有限結(jié)束進(jìn)程。
(4)解決辦法
這個(gè)redis進(jìn)程占用了近26G的內(nèi)存弟塞,而redis配置文件最大配置的內(nèi)存是20G凭峡,也就是除了20g數(shù)據(jù)占用的內(nèi)存,程序進(jìn)程本身占用了近6G的數(shù)據(jù)决记。我們服務(wù)器可用內(nèi)存是98G摧冀,之所以這次內(nèi)存會(huì)不夠用的原因是這臺(tái)服務(wù)器部署了5個(gè)redis節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)的最大可用內(nèi)存設(shè)置都是20G系宫,這次由于大量寫(xiě)入數(shù)據(jù)導(dǎo)致redis節(jié)點(diǎn)內(nèi)存暴增索昂。所以解決辦法就是減少部署的節(jié)點(diǎn),比如機(jī)器總共內(nèi)存是98G扩借,最多部署4個(gè)節(jié)點(diǎn)椒惨,還有就是增減內(nèi)存占用閾值報(bào)警監(jiān)控,另外就是大量數(shù)據(jù)寫(xiě)入前檢查機(jī)器節(jié)點(diǎn)內(nèi)存是否夠用潮罪。
擴(kuò)展
1.什么是oom killer
他是Linux內(nèi)核設(shè)計(jì)的一種機(jī)制康谆,在內(nèi)存不足的會(huì)后,選擇一個(gè)占用內(nèi)存較大的進(jìn)程并kill掉這個(gè)進(jìn)程错洁,以滿足內(nèi)存申請(qǐng)的需求(內(nèi)存不足的時(shí)候該怎么辦秉宿,其實(shí)是個(gè)兩難的事情,oom killer算是提供了一種方案吧)
2.在什么時(shí)候觸發(fā)屯碴?
在內(nèi)存不足的時(shí)候觸發(fā)描睦,再往細(xì)節(jié)看,主要牽涉到【linux的物理內(nèi)存結(jié)構(gòu)】和【overcommit機(jī)制】
2.1 內(nèi)存結(jié)構(gòu) node导而、zone忱叭、page、order
對(duì)于物理內(nèi)存內(nèi)存今艺,linux會(huì)把它分很多區(qū)(zone)韵丑,zone上還有node的概念,zone下面是很多page虚缎,這些page是根據(jù)buddy分配算法組織的
上面的概念做下簡(jiǎn)單的介紹撵彻,對(duì)后面分析oom killer日志很有必要:
Node:每個(gè)CPU下的本地內(nèi)存節(jié)點(diǎn)就是一個(gè)Node,如果是UMA架構(gòu)下实牡,就只有一個(gè)Node0,在NUMA架構(gòu)下陌僵,會(huì)有多個(gè)Node
Zone:每個(gè)Node會(huì)劃分很多域Zone,大概有下面這些
- ZONE_DMA:定義適合DMA的內(nèi)存域创坞,該區(qū)域的長(zhǎng)度依賴于處理器類型碗短。比如ARM所有地址都可以進(jìn)行DMA,所以該值可以很大题涨,偎谁,或者干脆不定義DMA類型的內(nèi)存域总滩。而在IA-32的處理器上,一般定義為16M巡雨。
- ZONE_DMA32:只在64位系統(tǒng)上有效闰渔,為一些32位外設(shè)DMA時(shí)分配內(nèi)存。如果物理內(nèi)存大于4G铐望,該值為4G澜建,否則與實(shí)際的物理內(nèi)存大小相同。
- ZONE_NORMAL:定義可直接映射到內(nèi)核空間的普通內(nèi)存域蝌以。在64位系統(tǒng)上炕舵,如果物理內(nèi)存小于4G,該內(nèi)存域?yàn)榭崭6?2位系統(tǒng)上咽筋,該值最大為896M。
- ZONE_HIGHMEM:只在32位系統(tǒng)上有效徊件,標(biāo)記超過(guò)896M范圍的內(nèi)存奸攻。在64位系統(tǒng)上,由于地址空間巨大虱痕,超過(guò)4G的內(nèi)存都分布在ZONE_NORMA內(nèi)存域睹耐。
- ZONE_MOVABLE:偽內(nèi)存域,為了實(shí)現(xiàn)減小內(nèi)存碎片的機(jī)制部翘。
分配價(jià)值鏈
- 除了只能在某個(gè)區(qū)域分配的內(nèi)存(比如ZONE_DMA)硝训,普通的內(nèi)存分配會(huì)有一個(gè)“價(jià)值”的層次結(jié)構(gòu),按分配的“廉價(jià)度”依次為:ZONE_HIGHMEM > ZONE_NORMAL > ZONE_DMA新思。
- 即內(nèi)核在進(jìn)行內(nèi)存分配時(shí)窖梁,優(yōu)先從高端內(nèi)存進(jìn)行分配,其次是普通內(nèi)存夹囚,最后才是DMA內(nèi)存
Page zone下面就是真正的內(nèi)存頁(yè)了纵刘,每個(gè)頁(yè)基礎(chǔ)大小是4K,他們維護(hù)在一個(gè)叫free_area的數(shù)組結(jié)構(gòu)中荸哟。
- order:數(shù)組的index假哎,也叫order,實(shí)際對(duì)應(yīng)的是page的大小鞍历,比如order為0舵抹,那么就是一堆1個(gè)空閑頁(yè)(4K)組成的鏈表,order為1堰燎,就是一堆2個(gè)空閑頁(yè)(8K)組成的鏈表掏父,order為2笋轨,就是一堆4個(gè)空閑頁(yè)(16K)組成的鏈表
2.2 overcommit
根據(jù)2.1秆剪,已經(jīng)知道物理內(nèi)存的大概結(jié)構(gòu)以及分配的規(guī)則赊淑,不過(guò)實(shí)際上還有虛擬內(nèi)存的存在,他的overcommit機(jī)制和oom killer有很大關(guān)系:
在實(shí)際申請(qǐng)內(nèi)存的時(shí)候仅讽,比如申請(qǐng)1G陶缺,并不會(huì)在物理區(qū)域中分配1G的真實(shí)物理內(nèi)存,而是分配1G的虛擬內(nèi)存洁灵,等到需要的時(shí)候才去真正申請(qǐng)物理內(nèi)存饱岸,也就是說(shuō)申請(qǐng)不等于分配
所以說(shuō),可以申請(qǐng)比物理內(nèi)存實(shí)際大的內(nèi)存徽千,也就是overcommit苫费,這樣會(huì)面臨一個(gè)問(wèn)題,就是當(dāng)真的需要這么多內(nèi)存的時(shí)候怎么辦—>oom killer!
vm.overcommit_memory 接受三種值:
- 0 – Heuristic overcommit handling. 這是缺省值双抽,它允許overcommit百框,但過(guò)于明目張膽的overcommit會(huì)被拒絕,比如malloc一次性申請(qǐng)的內(nèi)存大小就超過(guò)了系統(tǒng)總內(nèi)存
- 1 – Always overcommit. 允許overcommit牍汹,對(duì)內(nèi)存申請(qǐng)來(lái)者不拒铐维。
- 2 – Don’t overcommit. 禁止overcommit。
3.oom killer 怎么挑選進(jìn)程慎菲?
linux會(huì)為每個(gè)進(jìn)程算一個(gè)分?jǐn)?shù)嫁蛇,最終他會(huì)將分?jǐn)?shù)最高的進(jìn)程kill
/proc/<pid>/oom_score_adj
- 在計(jì)算最終的 badness score 時(shí),會(huì)在計(jì)算結(jié)果是中加上 oom_score_adj露该,取值范圍為-1000到1000
- 如果將該值設(shè)置為-1000睬棚,則進(jìn)程永遠(yuǎn)不會(huì)被殺死,因?yàn)榇藭r(shí) badness score 永遠(yuǎn)返回0解幼。
/proc/<pid>/oom_adj
- 取值是-17到+15闸拿,取值越高,越容易被干掉书幕。如果是-17新荤,則表示不能被kill
- 該設(shè)置參數(shù)的存在是為了和舊版本的內(nèi)核兼容
/proc/<pid>/oom_score
- 這個(gè)值是系統(tǒng)綜合進(jìn)程的內(nèi)存消耗量、CPU時(shí)間(utime + stime)台汇、存活時(shí)間(uptime - start time)和oom_adj計(jì)算出的苛骨,消耗內(nèi)存越多分越高,存活時(shí)間越長(zhǎng)分越低
子進(jìn)程內(nèi)存:
Linux在計(jì)算進(jìn)程的內(nèi)存消耗的時(shí)候苟呐,會(huì)將子進(jìn)程所耗內(nèi)存的一半同時(shí)算到父進(jìn)程中痒芝。這樣,那些子進(jìn)程比較多的進(jìn)程就要小心了牵素。
關(guān)閉 OOM killer
- sysctl -w vm.overcommit_memory=2
- echo “vm.overcommit_memory=2” >> /etc/sysctl.conf
3.1 找出最優(yōu)可能被殺掉的進(jìn)程
vi oomscore.sh
#!/bin/bash
for proc in $(find /proc -maxdepth 1 -regex '/proc/[0-9]+'); do
printf "%2d %5d %s\n" \
"$(cat $proc/oom_score)" \
"$(basename $proc)" \
"$(cat $proc/cmdline | tr '\0' ' ' | head -c 50)"
done 2>/dev/null | sort -nr | head -n 10
chmod +x oomscore.sh
./oomscore.sh
3.2 避免的oom killer的方案
- 直接修改/proc/PID/oom_adj文件严衬,將其置位-17
- 修改/proc/sys/vm/lowmem_reserve_ratio
- 直接關(guān)閉oom-killer