《LINUX教學(xué):深入理解操作系統(tǒng)內(nèi)存》要點(diǎn):
本文介紹了LINUX教學(xué):深入理解操作系統(tǒng)內(nèi)存,希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
圖片起源:http://www.tomshardware.com/
媒介:
Memory(內(nèi)存)是一臺(tái)計(jì)算機(jī)組成的重要部門,也是最基礎(chǔ)的一部門.其它基礎(chǔ)組件有主板、CPU、磁盤、顯卡(可獨(dú)立可集成)等.寫這篇文章源自后面的一個(gè)案例,出于想搞明白,以及分享以前關(guān)于內(nèi)存方面的一些記錄的知識(shí)點(diǎn).
本文概要主要講了內(nèi)存的介紹;如何正確查看系統(tǒng)內(nèi)存使用率;對(duì)Swap分區(qū)進(jìn)行介紹;如何將內(nèi)存當(dāng)作硬盤來(lái)加速數(shù)據(jù)讀寫,以及分享關(guān)于內(nèi)存異常的案例闡發(fā);介紹了oom-killer的機(jī)制.
一、內(nèi)存的先容
1.何為內(nèi)存
內(nèi)存 是一種利用半導(dǎo)體技術(shù)制成的存儲(chǔ)數(shù)據(jù)的電子設(shè)備.其電子電路中的數(shù)據(jù)以二進(jìn)制方式存儲(chǔ),內(nèi)存的每一個(gè)存儲(chǔ)單元稱做記憶元.內(nèi)存根據(jù)存儲(chǔ)才能及電源關(guān)系又可分為易失性內(nèi)存(斷電后丟失),非易失性內(nèi)存(斷電后持久).
2.內(nèi)存、CPU、磁盤三者的關(guān)系
二、如何正確查看內(nèi)存的使用率
1.free 敕令查看內(nèi)存使用
[root@docker ~]# free total used free shared buff/cache available Mem: 1883740 440288 896080 31024 547372 1256984 Swap: 0 0 0
注:本機(jī)已封閉swap分區(qū).
2.top 查看進(jìn)程使用的內(nèi)存
可指定過(guò)程查看,不加參數(shù)顯示所有的過(guò)程,以及概覽.
[root@docker ~]# top -p `pgrep nginx|head -n 1` ...省略 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 26826 root 20 0 45816 1000 0 S 0.0 0.1 0:00.00 nginx
注釋:
第一行,顯示了默認(rèn)的字段,另top狀態(tài)下,可輸入 f 鍵,進(jìn)行選擇其它字段,如DATA、SWAP等
第二行,顯示字段的值.這里說(shuō)下進(jìn)程RES (駐留內(nèi)存空間)和%MEM的關(guān)系,%MEM 是該進(jìn)程占用系統(tǒng)物理total內(nèi)存的百分比.RES計(jì)算方式:total*%MEM=RES;VIRT包含所需要的代碼、數(shù)據(jù)和共享庫(kù).
3.vmstat 查看虛擬內(nèi)存使用以及swap分區(qū) 和系統(tǒng)、cpu的io 申報(bào)
[root@docker ~]# vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 4 0 0 858708 15756 571772 0 0 6 49 16 0 8 0 92 0 0
?
三、Swap——與內(nèi)存緊密相關(guān)的互換空間
1.Swap 用途先容
當(dāng)物理內(nèi)存(RAM)的數(shù)量已滿時(shí),會(huì)使用Linux中的swap交換空間.如果系統(tǒng)需要更多內(nèi)存資源并且RAM已滿,則內(nèi)存中的非活動(dòng)頁(yè)面將移動(dòng)到交換空間中.雖然交換空間可以幫助機(jī)器使用少量的RAM,但不應(yīng)該被認(rèn)為是更多RAM的替代品.因?yàn)榻粨Q空間位于硬盤驅(qū)動(dòng)器上,拜訪時(shí)間比物理內(nèi)存慢的很多.發(fā)生的交換越多,系統(tǒng)越慢.
Linux有兩種形式的交換空間:交換分區(qū)和交換文件.交換分區(qū)是僅用于交換的硬盤的獨(dú)立部門,沒(méi)有其他文件可以存放在那里.交換文件是位于系統(tǒng)和數(shù)據(jù)文件之間在文件系統(tǒng)中的一個(gè)特殊文件.另外,swap 空間一般設(shè)置物理內(nèi)存的2倍.
2.啟用或禁止互換空間
3.如何啟用或禁用交換空間
查看當(dāng)前swap空間狀態(tài)
root@docker ~]# swapon -s 文件名 類型 年夜小 已用 權(quán)限 /mnt/os_swap file 4194300 0 -1
禁用swap空間
[root@docker ~]# swapoff -a
啟用swap空間(這里使用的文件情勢(shì)作為swap分區(qū))
[root@docker ~]# swapon /mnt/os_swap
4.創(chuàng)立swap分區(qū)大小
在當(dāng)前的文件系統(tǒng)里,用dd或者fallocate(更快更簡(jiǎn)單)創(chuàng)立一個(gè)用于swap分區(qū)的文件:
[root@docker ~]# dd if=/dev/zero of=/mnt/os_swap bs=1M count=4096
或
[root@docker ~]# fallocate -l 4G /mnt/os_swap
改動(dòng)該文件權(quán)限為600
[root@docker ~]# chmod 600 /mnt/os_swap
使用mkswap命令將文件建成一個(gè)交換空間(也可在最后用 -p size 指定劃分給swap空間的年夜小,默認(rèn)使用整個(gè)file 年夜小)
[root@docker ~]# mkswap /mnt/os_swap mkswap: /mnt/os_swap: warning: wiping old swap signature. 正在設(shè)置交換空間版本 1,年夜小 = 4194300 KiB 無(wú)標(biāo)簽,UUID=fc870bd5-c823-4e70-9d14-966543a52db2
使用swap分區(qū),并檢查swap空間年夜小
[root@docker ~]# swapon /mnt/os_swap [root@docker ~]# swapon -s 文件名 類型 大小 已用 權(quán)限 /mnt/os_swap file 4194300 0 -1
首先找到一個(gè)大小合適的磁盤分區(qū),分區(qū)類型選擇82-Linux Swap.然后之后和上述類似,用mkswap命令創(chuàng)立啟用swap分區(qū).并用swapon /dev/vdb1(vdb1為分區(qū)設(shè)備)命令啟用swap分區(qū).
?5.swappiness-系統(tǒng)什么時(shí)候開始使用互換空間
當(dāng)我們?cè)O(shè)置啟用swap分區(qū)后,系統(tǒng)會(huì)在什么情況下使用交換空間?這要從物理RAM內(nèi)存使用情況來(lái)看,系統(tǒng)內(nèi)核參數(shù)定義了這個(gè)界限:vm.swappiness,該參數(shù)取值范圍在0-100之間,它定義了當(dāng)系統(tǒng)剩余內(nèi)存是總內(nèi)存的多少百分比后,即開始使用交換空間.(暫時(shí)對(duì)這句話堅(jiān)持質(zhì)疑,經(jīng)過(guò)多方內(nèi)存使用的測(cè)試,系統(tǒng)在由RAM轉(zhuǎn)向Swap空間時(shí)并沒(méi)有一個(gè)固定的剩余內(nèi)存值!如你有相關(guān)計(jì)算方式,還望不吝賜教,謝謝!)
?vm.swappiness 默認(rèn)值是60.swappiness參數(shù)的值越高,表現(xiàn)內(nèi)核將會(huì)更積極地從內(nèi)存到交換空間中移動(dòng)數(shù)據(jù).經(jīng)測(cè)試
當(dāng)值為0時(shí),系統(tǒng)可用內(nèi)存在使用完后再使用swap進(jìn)行互換.
當(dāng)值為1時(shí),和0的區(qū)別不年夜.
保舉在數(shù)據(jù)庫(kù)讀寫數(shù)據(jù)密集的應(yīng)用中禁用swap交換空間或者設(shè)置更低的vm.swappiness值,避免更多的硬盤IO操作,以此作為提高讀寫速度的一個(gè)方式.
?
四、如何將內(nèi)存看成磁盤使用來(lái)加速數(shù)據(jù)讀寫
1.內(nèi)存文件體系介紹
圖片起源:www.thomas-krenn.com
如上圖所示,應(yīng)用內(nèi)存作為特殊文件系統(tǒng),目前知道的方式有3種,RAMdisk、ramfs、tmpfs.
ramdisk:RAM disk是使用主系統(tǒng)內(nèi)存作為塊設(shè)備的一種方式.它也可用于臨時(shí)文件系統(tǒng)的加密工作,因?yàn)閮?nèi)容在重新啟動(dòng)時(shí)將被擦除.由于這個(gè)塊設(shè)備大小是固定的,因此安裝寄存在其上面的文件系統(tǒng)是固定的大小.
ramfs:Ramfs是一個(gè)非常簡(jiǎn)單的文件系統(tǒng),用于導(dǎo)出Linux的磁盤緩存 機(jī)制(頁(yè)面緩存和dentry緩存)基于RAM的文件系統(tǒng),可以動(dòng)態(tài)的根據(jù)需要調(diào)整大小(前提不超過(guò)總RAM的情況).通常,文件都被Linux緩存在內(nèi)存中,數(shù)據(jù)頁(yè)從后備存儲(chǔ)(通常是安裝文件系統(tǒng)的塊設(shè)備)中讀取并被保留 防止它再次需要,但標(biāo)記為干凈(可自由使用的),以防萬(wàn)一 虛擬內(nèi)存系統(tǒng)需要其他內(nèi)存.但ramfs 是沒(méi)有后備存儲(chǔ)的,像往常一樣,寫入ramfs的文件分配 dentry和頁(yè)面緩存,但是沒(méi)有地方可寫.這意味著頁(yè)面從未被標(biāo)記為干凈,因此當(dāng)VM正在尋找回收內(nèi)存時(shí),它們不能被釋放 .除非關(guān)機(jī)斷電.
tmpfs:將所有文件保存在虛擬內(nèi)存中的文件系統(tǒng).tmpfs中的所有內(nèi)容都是臨時(shí)的,因?yàn)樵谀愕挠脖P上不會(huì)有文件被創(chuàng)建.如果卸載tmpfs實(shí)例, 存儲(chǔ)在其中的一切都丟失.如果你umount tmpfs文件系統(tǒng),存儲(chǔ)在里面的內(nèi)容將丟失.tmpfs可以將所有內(nèi)容放入內(nèi)核內(nèi)部緩存并增長(zhǎng)收縮以容納它包括的文件,并能夠交換不需要的頁(yè)面到swap交換空間.由于tmpfs 完全位于頁(yè)面緩存和交換中,所有tmpfs頁(yè)面將在/proc/meminfo 和‘shared’ 中顯示為 ”Shmem“
2.它們?nèi)暮?jiǎn)單比擬
ramfs與ramdisk比較:使用ram disk還需要不必要地將偽造塊設(shè)備中的內(nèi)存復(fù)制到頁(yè)面緩存(并復(fù)制更改),以及創(chuàng)建和銷毀dentries.此外,它還需要一個(gè)文件系統(tǒng)驅(qū)動(dòng)程序(如ext2)來(lái)格式化和解釋這些數(shù)據(jù).與ramfs相比,這浪費(fèi)了內(nèi)存(和內(nèi)存總線帶寬),為CPU創(chuàng)造了不必要的工作,并污染了CPU高速緩存.更重要的一點(diǎn),ramfs的所有的工作都發(fā)生在_anyway_,因?yàn)樗形募菰L都通過(guò)頁(yè)面和dentry緩存. RAM disk是不必要的; ramfs在內(nèi)部更簡(jiǎn)單,使用起來(lái)更靈活,大小可隨著需要的空間而動(dòng)態(tài)增加或減少.
ramfs與tmpfs比較:ramfs的一個(gè)缺點(diǎn)是你可以持續(xù)的往里面寫入數(shù)據(jù),直到填滿所有的內(nèi)存,并且VM無(wú)法釋放它,因?yàn)閂M認(rèn)為文件應(yīng)該寫入后備存儲(chǔ)(而不是交換空間),但是ramfs 它沒(méi)有任何后備存儲(chǔ).因此,只有root(或受信任的用戶)才允許對(duì)ramfs mount進(jìn)行寫拜訪.創(chuàng)建一個(gè)名為tmpfs的ramfs派生物,以增加大小限制和能力,將數(shù)據(jù)寫入swap交換空間.普通用戶也可以允許寫入權(quán)限?tmpfs掛載.
3.若何設(shè)置ramfs
創(chuàng)立一個(gè)目錄,用于掛載ramfs
[root@docker ~]# mkdir /ramfs_test
?掛載ramfs到上一步創(chuàng)立的目錄中
[root@docker ~]# mount -t ramfs ramfs /ramfs_test/ 檢查 [root@docker ~]# mount |grep ramfs_test ramfs on /ramfs_test type ramfs (rw,relatime)
測(cè)試一下ramfs與磁盤io讀寫的比擬,一目了然.
[root@docker ~]# dd if=/dev/zero of=/ramfs_test/testfile.ramfs bs=1M count=1000 記錄了1000+0 的讀入 記錄了1000+0 的寫出 1048576000字節(jié)(1.0 GB)已復(fù)制,0.60369 秒,1.7 GB/秒 [root@docker ~]# dd if=/dev/zero of=/tmp/testfile.ramfs bs=1M count=1000 記錄了1000+0 的讀入 記錄了1000+0 的寫出 1048576000字節(jié)(1.0 GB)已復(fù)制,13.3286 秒,78.7 MB/秒
另外一個(gè)必要說(shuō)明,網(wǎng)上大部分文章說(shuō)掛載ramfs時(shí),可以指定maxsize,即使用的最大的內(nèi)存,經(jīng)過(guò)測(cè)試,size(maxsize)參數(shù)沒(méi)有生效,我使用以下命令進(jìn)行掛載:
[root@docker ~]# mount -t ramfs ramfs /ramfs_test -o size=1024M && mount | grep ramfs ramfs on /ramfs_test type ramfs (rw,relatime,size=1024M)
然后放入一個(gè)年夜于1G的文件,并檢查年夜小
[root@docker ~]# dd if=/dev/zero of=/ramfs_test/testramfs.file bs=1M count=1200 記錄了1200+0 的讀入 記錄了1200+0 的寫出 1258291200字節(jié)(1.3 GB)已復(fù)制,0.78763 秒,1.6 GB/秒 [root@docker ~]# ll -h /ramfs_test/testramfs.file -rw-r--r-- 1 root root 1.2G 6月 2 09:04 /ramfs_test/testramfs.file
從上面可以看出,使用ramfs作文件系統(tǒng),并沒(méi)有受到限制,所以它有可能占用系統(tǒng)全部的RAM,并導(dǎo)致系統(tǒng)死鎖,無(wú)法進(jìn)行操作,系統(tǒng)內(nèi)核將崩潰.所以這里在使用ramfs時(shí),要慎重考慮使用場(chǎng)景,避免程序故障或內(nèi)存溢出導(dǎo)致系統(tǒng)崩潰,必須重啟才能辦理!另外查看了mount的man 手冊(cè),掛載ramfs內(nèi)容時(shí)只有以下內(nèi)容:
Mount options for ramfs Ramfs is a memory based filesystem. Mount it and you have it. Unmount it and it is gone. Present since Linux 2.3.99pre4. There are no mount options.
而,size參數(shù)只實(shí)用于tmpfs!
Mount options for tmpfs size=nbytes Override default maximum size of the filesystem. The size is given in bytes, and rounded up to entire pages. The default is half of the memory. The size parameter also accepts a suffix % to limit this tmpfs instance to that percentage of your physical RAM: the default, when neither size nor nr_blocks is specified, is size=50%?
4.若何設(shè)置tmpfs
和ramfs有點(diǎn)類似,先創(chuàng)立一個(gè)目錄,用于掛載tmpfs
[root@docker ~]# mkdir /tmpfs_test
使用mount命令掛載到tmpfs_test目錄中,并反省掛載情況
[root@docker ~]# mount -t tmpfs -o size=1G tmpfs /tmpfs_test && mount |grep tmpfs_test tmpfs on /tmpfs_test type tmpfs (rw,relatime,size=1048576k)
現(xiàn)在我們使用dd來(lái)測(cè)試一下速度,并反省下size 限制空間的效果
[root@docker ~]# dd if=/dev/zero of=/tmpfs_test/testtmpfs.file bs=1M count=1100 dd: error writing ‘/tmpfs_test/testtmpfs.file’: No space left on device 1025+0 records in 1024+0 records out 1073741824 bytes (1.1 GB) copied, 0.497443 s, 2.2 GB/s
從上面的提示可以看出,空間已經(jīng)不夠,現(xiàn)在看下實(shí)際存入的文件年夜小
[root@docker ~]# ls -l --block-size=K /tmpfs_test/testtmpfs.file -rw-r--r-- 1 root root 1048576K Jun 2 12:16 /tmpfs_test/testtmpfs.file
從ls的輸出可以看到,實(shí)際存入的文件大小,剛好是size限制的大小.很明顯,size起到了避免系統(tǒng)RAM/SWAP內(nèi)存被tmpfs 全部填滿的情況.也體現(xiàn)了tmpfs 比ramfs的優(yōu)勢(shì)所在.所以保舉使用tmpfs.?
下面是之前tmpfs先容中所說(shuō)的tmpfs在/proc/meminfo 以及shared 顯示.
[root@docker ~]# free -m && echo '-------------------------/proc/meminfo' && cat /proc/meminfo |grep Shmem total used free shared buff/cache available Mem: 1839 268 174 1024 1397 393 Swap: 0 0 0 -------------------------/proc/meminfo Shmem: 1048964 kB
?
五、常見內(nèi)存不敷或內(nèi)存溢出導(dǎo)致的故障分析
1.一次內(nèi)存非常導(dǎo)致應(yīng)用被kill的案例
某臺(tái)應(yīng)用無(wú)法提供服務(wù),主機(jī)sshd無(wú)法拜訪,通信異常.使用vnc連接到本地終端后,發(fā)現(xiàn)終端界面上報(bào)以下錯(cuò)誤日志,也無(wú)法進(jìn)行操作:
INFO: task sh:12628 blocked for more than 120 seconds.Not tainted 2.6.32-431.el6.x86 #1 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
上述錯(cuò)誤,只是警告提示,跟系統(tǒng)內(nèi)核參數(shù)vm.dirty_ratio有關(guān)系,后面會(huì)專門的介紹. 由于該主機(jī)無(wú)法響應(yīng)任何操作,系統(tǒng)也登陸不進(jìn)去,只有斷電重啟了(這里也可看出系統(tǒng)日志收集到某個(gè)中心節(jié)點(diǎn)的好處Y(^_^)Y).重啟后觀察系統(tǒng)messages日志,下面是日志的一部門,這里有完整的日志,有興趣的可以下載看下:
May 19 00:31:07 robot-web kernel: VFS: file-max limit 65535 reached May 19 00:31:30 robot-web kernel: VFS: file-max limit 65535 reached May 19 00:32:24 robot-web kernel: sh invoked oom-killer: gfp_mask=0x84d0, order=0, oom_adj=0, oom_score_adj=0 May 19 00:32:24 robot-web kernel: sh cpuset=/ mems_allowed=0 May 19 00:32:24 robot-web kernel: Pid: 20387, comm: sh Not tainted 2.6.32-431.el6.x86_64 #1 May 19 00:32:24 robot-web kernel: Call Trace: May 19 00:32:24 robot-web kernel: [<ffffffff810d05b1>] ? cpuset_print_task_mems_allowed+0x91/0xb0 May 19 00:32:24 robot-web kernel: [<ffffffff81122960>] ? dump_header+0x90/0x1b0 May 19 00:32:24 robot-web kernel: [<ffffffff8122798c>] ? security_real_capable_noaudit+0x3c/0x70 May 19 00:32:24 robot-web kernel: [<ffffffff81122de2>] ? oom_kill_process+0x82/0x2a0 May 19 00:32:24 robot-web kernel: [<ffffffff81122d21>] ? select_bad_process+0xe1/0x120 May 19 00:32:24 robot-web kernel: [<ffffffff81123220>] ? out_of_memory+0x220/0x3c0 May 19 00:32:24 robot-web kernel: [<ffffffff8112fb3c>] ? __alloc_pages_nodemask+0x8ac/0x8d0 May 19 00:32:24 robot-web kernel: [<ffffffff81167a9a>] ? alloc_pages_current+0xaa/0x110 May 19 00:32:24 robot-web kernel: [<ffffffff8104ee9b>] ? pte_alloc_one+0x1b/0x50 May 19 00:32:24 robot-web kernel: [<ffffffff81146412>] ? __pte_alloc+0x32/0x160 May 19 00:32:24 robot-web kernel: [<ffffffff8114b220>] ? handle_mm_fault+0x1c0/0x300 May 19 00:32:24 robot-web kernel: [<ffffffff8104a8d8>] ? __do_page_fault+0x138/0x480 May 19 00:32:24 robot-web kernel: [<ffffffff8152d45e>] ? do_page_fault+0x3e/0xa0 May 19 00:32:24 robot-web kernel: [<ffffffff8152a815>] ? page_fault+0x25/0x30 May 19 00:32:24 robot-web kernel: [<ffffffff8152d45e>] ? do_page_fault+0x3e/0xa0 May 19 00:32:24 robot-web kernel: [<ffffffff8152a815>] ? page_fault+0x25/0x30 May 19 00:32:24 robot-web kernel: Mem-Info: May 19 00:32:24 robot-web kernel: Node 0 DMA per-cpu: May 19 00:32:24 robot-web kernel: CPU 0: hi: 0, btch: 1 usd: 0 May 19 00:32:24 robot-web kernel: CPU 1: hi: 0, btch: 1 usd: 0 May 19 00:32:24 robot-web kernel: CPU 2: hi: 0, btch: 1 usd: 0 May 19 00:32:24 robot-web kernel: CPU 3: hi: 0, btch: 1 usd: 0 May 19 00:32:24 robot-web kernel: Node 0 DMA32 per-cpu: May 19 00:32:24 robot-web kernel: CPU 0: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 1: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 2: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 3: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: Node 0 Normal per-cpu: May 19 00:32:24 robot-web kernel: CPU 0: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 1: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 2: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 3: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: active_anon:1459499 inactive_anon:284686 isolated_anon:0 May 19 00:32:24 robot-web kernel: active_file:54 inactive_file:45 isolated_file:0 May 19 00:32:24 robot-web kernel: unevictable:0 dirty:0 writeback:0 unstable:0 May 19 00:32:24 robot-web kernel: free:26212 slab_reclaimable:6599 slab_unreclaimable:53001 May 19 00:32:24 robot-web kernel: mapped:697 shmem:793 pagetables:131666 bounce:0 May 19 00:32:24 robot-web kernel: Node 0 DMA free:15728kB min:124kB low:152kB high:184kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15340kB 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 writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes May 19 00:32:24 robot-web kernel: lowmem_reserve[]: 0 3000 8050 8050 May 19 00:32:24 robot-web kernel: Node 0 DMA32 free:45816kB min:25140kB low:31424kB high:37708kB active_anon:1983180kB inactive_anon:496216kB active_file:28kB inactive_file:72kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3072092kB mlocked:0kB dirty:0kB writeback:0kB mapped:2000kB shmem:1912kB slab_reclaimable:3200kB slab_unreclaimable:82768kB kernel_stack:10296kB pagetables:147684kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:1 all_unreclaimable? no May 19 00:32:24 robot-web kernel: lowmem_reserve[]: 0 0 5050 5050 May 19 00:32:24 robot-web kernel: Node 0 Normal free:43304kB min:42316kB low:52892kB high:63472kB active_anon:3854816kB inactive_anon:642528kB active_file:188kB inactive_file:108kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:5171200kB mlocked:0kB dirty:0kB writeback:0kB mapped:788kB shmem:1260kB slab_reclaimable:23196kB slab_unreclaimable:129236kB kernel_stack:26800kB pagetables:378980kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:59 all_unreclaimable? no May 19 00:32:24 robot-web kernel: lowmem_reserve[]: 0 0 0 0 May 19 00:32:24 robot-web kernel: Node 0 DMA: 2*4kB 1*8kB 2*16kB 2*32kB 2*64kB 1*128kB 0*256kB 0*512kB 1*1024kB 1*2048kB 3*4096kB = 15728kB May 19 00:32:24 robot-web kernel: Node 0 DMA32: 340*4kB 76*8kB 461*16kB 264*32kB 132*64kB 62*128kB 12*256kB 5*512kB 0*1024kB 1*2048kB 1*4096kB = 45952kB May 19 00:32:24 robot-web kernel: Node 0 Normal: 9334*4kB 326*8kB 2*16kB 8*32kB 4*64kB 2*128kB 2*256kB 0*512kB 0*1024kB 1*2048kB 0*4096kB = 43304kB May 19 00:32:24 robot-web kernel: 30346 total pagecache pages May 19 00:32:24 robot-web kernel: 29453 pages in swap cache May 19 00:32:24 robot-web kernel: Swap cache stats: add 691531, delete 662078, find 1720814/1738009 May 19 00:32:24 robot-web kernel: Free swap = 0kB May 19 00:32:24 robot-web kernel: Total swap = 2064376kB May 19 00:32:24 robot-web kernel: 0 8384 26517 56 1 0 0 sh May 19 00:32:24 robot-web kernel: [ 8385] 0 8385 64694 2309 2 0 0 php May 19 00:32:24 robot-web kernel: [ 8386] 0 8386 26517 56 2 0 0 sh May 19 00:32:24 robot-web kernel: [ 8387] 0 8387 26517 57 0 0 0 sh May 19 00:32:24 robot-web kernel: [ 8388] 0 8388 26517 55 1 0 0 sh May 19 00:32:24 robot-web kernel: [ 8402] 0 8402 26517 56 0 0 0 sh May 19 00:32:24 robot-web kernel: [ 8887] 93 8887 23967 272 1 0 0 sendmail May 19 00:32:24 robot-web kernel: [15917] 0 15917 64760 2347 3 0 0 php May 19 00:32:24 robot-web kernel: [15921] 0 15921 64760 2351 3 0 0 php May 19 00:32:24 robot-web kernel: [15923] 0 15923 64760 2349 2 0 0 php May 19 00:32:24 robot-web kernel: [15925] 0 15925 64696 2343 3 0 0 php May 19 00:32:24 robot-web kernel: [15950] 0 15950 64760 2346 3 0 0 php
1 May 19 00:31:30 robot-web kernel: VFS: file-max limit 65535 reached 2 ... 3 4 May 19 00:32:24 robot-web kernel: Free swap = 0kB 5 May 19 00:32:24 robot-web kernel: Total swap = 2064376kB 6 ... 7 8 May 19 00:32:24 robot-web kernel: [20477] 0 20477 26518 55 3 0 0 sh 9 May 19 00:32:24 robot-web kernel: Out of memory: Kill process 1572 (mysqld) score 3 or sacrifice child 10 May 19 00:32:24 robot-web kernel: Killed process 1572, UID 500, (mysqld) total-vm:452564kB, anon-rss:5400kB, file-rss:40kB 11 May 19 00:32:24 robot-web kernel: sh invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
重啟系統(tǒng)恢復(fù)正常后,根據(jù)以上出現(xiàn)的問(wèn)題,對(duì)系統(tǒng)進(jìn)行了調(diào)優(yōu)工作.主要包含以下幾個(gè)部分:
臨時(shí): echo 0 > /proc/sys/kernel/hung_task_timeout_secs 或 sysctl -w hung_task_timeout_secs=0 永久 echo “kernel.hung_task_timeout_secs = 0” >>/etc/sysctl.conf sysctl -p
增加系統(tǒng)物理內(nèi)存到16G,并修改用戶open files限制數(shù)為1048576 計(jì)算是每4M內(nèi)存打開256個(gè)文件數(shù),即:(16G*1024)M/4M *256.
臨時(shí): ulimit -n 1048576 或 echo "ulimit -n 1048576" >> /etc/profile 永久:編寫/etc/security/limits.conf,根據(jù)提示在末行添加
臨時(shí): echo 1048576 > /proc/sys/fs/file-max 或 sysctl -w fs.file-max=1048576 永久 echo “fs.file-max=1048576” >> /etc/sysctl.conf sysctl -p
臨時(shí): sysctl -w vm.dirty_background_ratio=5 sysctl -w vm.dirty_ratio=10 永久: echo "vm.dirty_background_ratio=5" >> /etc/sysctl.conf echo "vm.dirty_ratio=10" >> /etc/sysctl.conf
sysctl -p?
做了以上修改優(yōu)化后,系統(tǒng)到目前為止,沒(méi)有出現(xiàn)過(guò)異常.
2.對(duì)以上參數(shù)修改進(jìn)行闡發(fā)
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message
先說(shuō)下這個(gè)吧.關(guān)于內(nèi)核為什么提示我們要“改動(dòng)這個(gè)時(shí)間為0,來(lái)禁用這條消息”的提示.先看下hung_task_timeout_secs的介紹,參考內(nèi)核文檔:
hung_task_timeout_secs: Check interval. When a task in D state did not get scheduled for more than this value report a warning. This file shows up if CONFIG_DETECT_HUNG_TASK is enabled. 0: means infinite timeout - no checking done. Possible values to set are in range {0..LONG_MAX/HZ}.
內(nèi)核定時(shí)檢測(cè)系統(tǒng)中處于D狀態(tài)的進(jìn)程,如果其處于D狀態(tài)的時(shí)間跨越了指定時(shí)間(默認(rèn)120s,可以配置),則打印相關(guān)堆棧信息,也可以通過(guò)proc參數(shù)配置使其直接panic.
默認(rèn)情況下,Linux使用高達(dá)40%的可用內(nèi)存將進(jìn)行文件系統(tǒng)緩存.達(dá)到此標(biāo)記后,文件系統(tǒng)將所有未完成的數(shù)據(jù)刷新到磁盤,導(dǎo)致所有的IO進(jìn)行同步.要將此數(shù)據(jù)刷新到磁盤,默認(rèn)情況下有120秒的時(shí)間限制.在這種情況下,IO子系統(tǒng)速度不夠快,可以有120秒的時(shí)間刷新數(shù)據(jù).由于IO子系統(tǒng)響應(yīng)緩慢,并且用戶進(jìn)程又提出了更多的哀求,系統(tǒng)內(nèi)存將被填滿,從而導(dǎo)致上述截圖中的錯(cuò)誤提示.
將其值修改為 0,意味著表示可以無(wú)限超時(shí)--不檢查完成情況.但此并不能真正的辦理問(wèn)題根源.
與hung_task其相關(guān)的幾個(gè)參數(shù)
這里只說(shuō)下此中兩個(gè)相關(guān)的參數(shù):vm.dirty_ratio 、vm.dirty_background_ratio,以下內(nèi)容出自Linux內(nèi)核文檔介紹:
dirty_background_ratio Contains, as a percentage of total available memory that contains free pages and reclaimable pages, the number of pages at which the background kernel flusher threads will start writing out dirty data. The total available memory is not equal to total system memory. ============================================================== dirty_ratio Contains, as a percentage of total available memory that contains free pages and reclaimable pages, the number of pages at which a process which is generating disk writes will itself start writing out dirty data. The total available memory is not equal to total system memory.
dirty_background_ratio:是系統(tǒng)總內(nèi)存的占用百分比,其中包含空閑頁(yè)面和可回收頁(yè)面.后臺(tái)內(nèi)核刷新線程的頁(yè)面開始寫入臟數(shù)據(jù).即dirty data如果達(dá)到了dirty_background_ratio,則內(nèi)核將在后臺(tái)執(zhí)行回寫磁盤,但是應(yīng)用程序仍然可以在不阻塞的情況下寫入頁(yè)面緩存.
dirty_ratio:包括可用頁(yè)面和可回收頁(yè)面的占 總可用內(nèi)存的百分比,產(chǎn)生磁盤寫入的進(jìn)程將自動(dòng)開始寫入臟數(shù)據(jù).這時(shí)應(yīng)用程序?qū)⒆枞⑴K頁(yè)面寫入磁盤.直到系統(tǒng)內(nèi)的dirty page低于該值.
即先達(dá)到dirty_background_ratio,這是程序不會(huì)阻塞,等到達(dá)dirty_ratio時(shí),程序?qū)⒆枞?直到將數(shù)據(jù)寫入磁盤中.這些參數(shù)的值取決于系統(tǒng)的運(yùn)行的什么程序,如果運(yùn)行大型數(shù)據(jù)庫(kù),建議將這些值保持小數(shù)值 background_ratio < dirty_ratio,以避免I/O瓶頸以及增加系統(tǒng)負(fù)載.這也是作為系統(tǒng)VM優(yōu)化的一個(gè)點(diǎn).
?
說(shuō)下file-max
sysctl -w fs.file-max=1048576
file-max中的值表示Linux內(nèi)核將要分配的文件句柄的最大數(shù)量. 每當(dāng)應(yīng)用程序哀求文件句柄時(shí),內(nèi)核會(huì)動(dòng)態(tài)分配文件句柄,但內(nèi)核在應(yīng)用程序關(guān)閉時(shí)并不會(huì)釋放銷毀這些文件句柄.內(nèi)核會(huì)循環(huán)使用這些文件句柄.也意味著隨著時(shí)間的推移,分配的文件句柄的總數(shù)將增加,即使當(dāng)前使用的文件句柄的數(shù)量可能較低.所以當(dāng)您收到大量關(guān)于運(yùn)行文件句柄的錯(cuò)誤消息時(shí),可能需要增加file-max值的大小.
?
3.什么是oom-killer ?
先容
OOM(Out Of Memory)?Management:它有一個(gè)簡(jiǎn)單的任務(wù)->檢查系統(tǒng)是否有足夠的可用內(nèi)存來(lái)滿足應(yīng)用程序,驗(yàn)證系統(tǒng)是否真的是內(nèi)存不敷,如果是這樣,請(qǐng)‘選擇’一個(gè)進(jìn)程來(lái)殺死它.
當(dāng)檢查可用內(nèi)存時(shí),所需頁(yè)面的數(shù)量作為參數(shù)傳遞給vm_enough_memory().除非系統(tǒng)管理員指定系統(tǒng)應(yīng)該過(guò)度使用內(nèi)存,不然將檢查可用內(nèi)存的安裝.為了確定有多少頁(yè)是潛在可用的,Linux總結(jié)了以下幾個(gè)關(guān)注數(shù)據(jù):
Total page cache 因?yàn)轫?yè)面緩存容易回收
Total free pages?因?yàn)樗鼈円呀?jīng)是有效可利用的
Total free swap pages 作為用戶空間的頁(yè)面可能會(huì)被分頁(yè)換出
Total pages managed by swapper_space?盡管這重復(fù)計(jì)算了空閑的交換頁(yè)面.這是平衡的,因?yàn)槭聦?shí)上,插槽有時(shí)是保存的,但沒(méi)有在使用.
Total pages used by the dentry cache?易于回收的
Total pages used by the inode cache?易于回收的
如果以上添加的總頁(yè)數(shù)足以滿足哀求,vm_enough_memory()函數(shù)將返回true給調(diào)用者.如果返回false,調(diào)用者就知道內(nèi)存不可用,通常決定將-ENOMEM返回給用戶空間.這時(shí)機(jī)器內(nèi)存不足時(shí),舊的頁(yè)幀將被回收,但是盡管回收頁(yè)面可能會(huì)發(fā)現(xiàn)還是無(wú)法釋放足夠的頁(yè)面來(lái)滿足哀求,如果它無(wú)法釋放頁(yè)面幀,則調(diào)用out_of_memory() 函數(shù)來(lái)查看系統(tǒng)是否內(nèi)存不足,并且還需要kill某進(jìn)程.
不巧的是,有可能系統(tǒng)在沒(méi)有空閑內(nèi)存可用時(shí),只必要等待IO完成 或頁(yè)面交換到后備存儲(chǔ)器中(如硬盤).所以為了防止誤殺情況,在決定殺死一個(gè)進(jìn)程之前,它將通過(guò)以下清單檢查:
只有上述測(cè)試通過(guò)了,能力調(diào)用oom_kill()來(lái)選擇一個(gè)進(jìn)程kill.
以上是2.6內(nèi)核以前的幾個(gè)存眷數(shù)據(jù),2.6內(nèi)核以后的,將以下信息片段添加在一起以確定可用內(nèi)存:
Total page cache?因?yàn)轫?yè)面緩存容易收受接管
Total free pages?因?yàn)樗鼈円呀?jīng)是有效可利用的
Total free swap pages?作為用戶空間的頁(yè)面可能會(huì)被分頁(yè)換出
Slab pages with SLAB_RECLAIM_ACCOUNT set?他們是容易收受接管的
這些頁(yè)面減去根進(jìn)程的3%預(yù)留內(nèi)存,就是可用于哀求的總內(nèi)存量.如果內(nèi)存可用,則進(jìn)行檢查以確保已提交內(nèi)存的總量不超過(guò)允許的閾值.
允許的閾值為TotalRam *(OverCommitRatio / 100)+ TotalSwapPage,其中OverCommitRatio 由系統(tǒng)管理員設(shè)置.
以上內(nèi)容參考Mel Gorman的冊(cè)本<<Understanding the Linux Virtual Memory Manager>>
注:
對(duì)swapper_space作個(gè)解釋備注,當(dāng)釋放不消的物理頁(yè)面時(shí),內(nèi)核并不會(huì)立即將其放入空閑隊(duì)列(free_area),而是將其插入非活動(dòng)隊(duì)列l(wèi)ru,便于再次時(shí)能夠快速的得到.swapper_space則用于記錄換入/換出到磁盤交換文件中的物理頁(yè)面.swapper_space是3個(gè)全局的LRU隊(duì)列其中之一
對(duì)dentry(翻譯:目錄項(xiàng))的解釋:它們用來(lái)實(shí)現(xiàn)名稱和 inode 之間的映射,有一個(gè)目錄緩存用來(lái)保留最近使用的 dentry.dentry 還維護(hù)目錄和文件之間的關(guān)系,從而支持在文件系統(tǒng)中移動(dòng)
4.為什么oom_killer選擇了mysqld過(guò)程?
函數(shù)select_bad_process()負(fù)責(zé)選擇要?dú)⑺赖倪M(jìn)程.badness() 已改oom_badness()通過(guò)為其檢查每個(gè)進(jìn)程累加的“ponits”并將其返回給select_bad_process().'points'數(shù)值最高的進(jìn)程,最終會(huì)被銷毀kill,除非它已經(jīng)在本身釋放內(nèi)存中.
進(jìn)程的得分值始于其常駐內(nèi)存的大小,任何子進(jìn)程(內(nèi)核線程除外)的獨(dú)立內(nèi)存大小也會(huì)添加到該分?jǐn)?shù)中;另外root 進(jìn)程在計(jì)算時(shí)將會(huì)有3%的優(yōu)惠,確保超級(jí)用戶的進(jìn)程不被殺掉.進(jìn)程的nice值會(huì)乘2計(jì)算得分,如果nice大于0即更有可能被選中;長(zhǎng)時(shí)間運(yùn)行的進(jìn)程的分?jǐn)?shù)會(huì)降低,運(yùn)行時(shí)間越長(zhǎng),被選中機(jī)率越低;直接拜訪硬件設(shè)備的進(jìn)程分?jǐn)?shù)會(huì)降低.?(刪除原因,是在Github上看到新的oom_kill.c文件中,已去掉了相關(guān)代碼).最后,累積的得分由/proc/pid/oom_score存儲(chǔ),且該文件對(duì)用戶只讀權(quán)限.
以下是oom_kill.c文件中關(guān)于oom_badness部門的代碼:
另外,在oom_kill.h文件中,/proc/pid/oom_adj 有取值范圍 -16~15 之間. -17表示對(duì)此進(jìn)程禁用oom.我們可以修改oom_adj的值,來(lái)掩護(hù)某指定的重要程序.?
如何檢測(cè)系統(tǒng)有無(wú)被oom-killer殺死的法式:可查看系統(tǒng)messages日志,以及用dmesg命令.另外還可以用dstat命令來(lái)查看當(dāng)前系統(tǒng)中,被oom機(jī)制選中的候選者,如下:
[root@docker ~]# dstat --top-oom --out-of-memory--- kill score mysqld 61 mysqld 61
六、總結(jié)
內(nèi)存管理是Linux系統(tǒng)內(nèi)核中核心技術(shù),重要性不言而喻,對(duì)內(nèi)存的了解越深,更有利于我們應(yīng)用程序的開發(fā)以及運(yùn)行.文中的內(nèi)容部分理論知識(shí)來(lái)自互聯(lián)網(wǎng)(鏈接在文末),另外也加入了本身的分析測(cè)試?yán)斫?本著深入學(xué)習(xí)的心理,寫下并總結(jié)了這篇文章分享給大家.如果文章中有錯(cuò)誤的地方,或者可以修改成更好的話來(lái)表達(dá),還望大家不吝賜教,留言私信都可以哈.另外感謝虎神給文章起的名字?? ?(:對(duì),你沒(méi)看錯(cuò),確實(shí)是寫完之后才想的名字,主要是內(nèi)存涉及了太多知識(shí),我覺(jué)得本文也只是描述了個(gè)大概.)?
參考銜接:
https://serverfault.com/questions/85470/meaning-of-the-buffers-cache-line-in-the-output-of-free
https://www.linux.com/news/all-about-linux-swap-space
https://askUbuntu.com/questions/103915/how-do-i-configure-swappiness
https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt
https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt
https://www.kernel.org/doc/Documentation/blockdev/ramdisk.txt
http://www.vpsee.com/2013/10/how-to-configure-the-linux-oom-killer/
http://www.adminlinux.org/2009/09/tuning-rhel-4xx-5xx-file-max-maximum.html
https://www.kernel.org/doc/Documentation/sysctl/fs.txt
https://www.blackmoreops.com/2014/09/22/linux-kernel-panic-issue-fix-hung_task_timeout_secs-blocked-120-seconds-problem/
https://www.kernel.org/doc/Documentation/sysctl/vm.txt
https://msdn.microsoft.com/en-us/library/bb742613.aspx
http://www.linuxatemyram.com/index.html
http://andylin02.iteye.com/blog/858708
https://lonesysadmin.net/2013/12/22/better-linux-disk-caching-performance-vm-dirty_ratio/
https://linux-mm.org/OOM_Killer
https://www.kernel.org/doc/gorman/html/understand/understand016.html
https://github.com/torvalds/linux/blob/dd23f273d9a765d7f092c1bb0d1cd7aaf668077e/Documentation/filesystems/proc.txt
本文永遠(yuǎn)更新鏈接地址:
學(xué)習(xí)更多LINUX教程,請(qǐng)查看站內(nèi)專欄,如果有LINUX疑問(wèn),可以加QQ交流《LINUX教學(xué):深入理解操作系統(tǒng)內(nèi)存》。
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.snjht.com/jiaocheng/9312.html