前言
不知道大家看完前面一章關於CPU優化,是否受到相應的啟發呢?如果遇到任何問題,可以留言和一起探討這方面的問題。接下來我們介紹一些關於內存方面的知識。內存管理軟件包括虛擬內存系統、地址轉換、交換、換頁和分配。與性能密切相關的內容包括:內存釋放、空閑鏈表、頁掃描、交換、進程地址空間和內存分配器。在Linux中,空閑鏈表通常由分配器消耗,如內核的slab分配器和SLUB,以及用戶級分配器(glibc,linux系統)libmalloc、libumem和mtmalloc。
- slab: 內核slab分配器管理特定大小的對象緩存,使他們能夠被快速的回收利用,並且避免頁分配的開銷。適用於處理固定大小結構的內核內存分配。
- slub: 基於slab分配器。它主要是解決slab分配器帶來的問題,其中包括移除對象隊列,以及每個CPU緩存,把NUMA優化留給頁分配器。
- glibc: 結合多種非配器策略的高效分配器,它基於分配請求的長度進行分配。較小的分配來自內存集合,包括用伙伴關系算法合並長度相近的單位。較大的分配用樹高效地搜索空間。對於非常大的分配,會轉到mmap()。
回收大多是從內核的slab分配器緩存釋放內存。這些緩存包含slab大小的未使用內存塊,以供充裕。內核頁面換出守護進程管理利用換頁釋放內存。當主存中可用的空閑鏈表低於閾值時,頁面換出守護進程會開始頁掃描。頁面換出守護進程被稱作kswapd(),它掃描非活動和活動內存的LRU頁列表以釋放頁面。它的激活基於空閑內存核兩個提供滯后的閾值。一旦空閑內存達到最低閾值,kswapd運行於同步模式,按需求釋放內存頁。該最低閾值是可調的(vm.min_free_kbytes),並且其他閾值基於它按比例放大。
相關概念
- 主存:物理內存,描述了計算機的告訴數據存儲區域,通常是動態隨機訪問內存;
- 虛擬內存: 抽象的主從概念,它幾乎是無限的和非競爭性的;
- 常駐內存:當前處於主存中的內存;
- 匿名內存:無文件系統位置或者路徑名的內存。它包括進程地址空間的工作數據,稱作堆;
- 地址空間:內存上下文。每個進程和內核都有對應的虛擬地址空間;
- 頁:操作系統和CPU使用的內存單位。它一直以來是4KB和8KB。現代的處理器允許多種頁大小以支持更大的頁面尺寸,以及更大的透明大頁;
- 缺頁:無效的內存訪問;
- 換頁:在主存與存儲設備間交換頁;
- 交換:指頁面從主從轉移到交換設備(遷移交換頁);
- 交換(空間):存放換頁的匿名數據和交換進程的磁盤空間;
進程地址空間是一段范圍的虛擬頁,由硬件和軟件同事管理,按需映射到物理頁。這些地址被划分為段以存放線程棧、進程可執行、庫和堆。應用程序可執行段包括分離的文本和數據段。庫也由分離的可執行文本和數據段組成。分別如下:
- 可執行文本:包括可執行的進程CPU指令。由文件系統中的二進制應用程序文本映射而來。它是只讀的並帶有執行的權限。
- 可執行數據:包括已初始化的變量,由二進制應用程序的數據段映射而來。有讀寫權限,因此這些變量在應用程序的運行過程中可以被修改。
- 堆:應用程序的臨時工作內存並且是匿名內存。它按需增長並且用mollac()分配。
- 棧:運行中的線程棧,映射為讀寫。
對於內存而言,經常關注的信息如下:
- 頁掃描:尋找連續的頁掃描(超過10秒),它是內存壓力的預兆。可以使用sar -B並查看pgscan列。
- 換頁:換頁是系統內存低的進一步征兆。可以使用vmstat 並查看si(換入) 和 so(換出)列。
- 可用內存:查看和關注buffer和cache值;
- OOM終結者:在系統日志/var/log/messages或者dmesg中查看,直接搜索"Out of memory";
- top/prstat:查看那些進程和用戶是常駐物理內存和虛擬內存的最大使用者;
- stap/perf:內存分配的棧跟蹤,確認內存使用的原因;
如何快速定位內存故障?
1. 首先應該檢查飽和度(作為釋放內存壓力的衡量,頁掃描、換頁、交換和Linux OOM終結者犧牲進度的使用程度),因為持續飽和狀態是內存問題的征兆。這些指標可以通過vmstat、sar、dmesg等操作系統工具輕易獲得。對於配置了獨立磁盤交換設備的系統,任何交換設備活動都是內存壓力的征兆。
2. 使用率(使用內存和可用內存,物理內存和虛擬內存都應該關注)通常較難讀取和解讀。比如一個系統可能會報告只有幾十兆內存可用,但事實上它有10GB的文件系統緩存在,需要時立刻被應用程序回收利用。虛擬內存使用,這應該也是我們關注的一個點。
3. 內存錯誤(Out of memory)一般都是由應用程序報告。
關於內存性能排查命令
vmstat
[root@zbredis-30104 ~]# vmstat procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 14834208 158384 936512 0 0 0 0 1 3 0 0 100 0 0
提示:
swpd:交換處的內存量;
free:空閑的可用內存;
buff: 用戶緩沖緩存的內存;
cache: 用於頁緩存的內存;
si: 換入的內存(換頁);
so:換出的內存(換頁);
如果si 和 so列一直非0,那么系統正存在內存壓力並換頁到交換設備或文件。經常使用參數為"vmstat 1 -Sm"和"vmstat -a 1";
sar
-B: 換頁統計信息;
-H: 大頁面統計信息
-r: 內存使用率
-R:內存統計信息
-S:交換空間統計信息
-W:交換統計信息
slabtop
通過slab分配器實時輸出內核slab緩存使用情況;
[root@localhost ~]# slabtop -sc Active / Total Objects (% used) : 297064 / 300262 (98.9%) Active / Total Slabs (% used) : 6638 / 6638 (100.0%) Active / Total Caches (% used) : 66 / 96 (68.8%) Active / Total Size (% used) : 80612.41K / 81749.09K (98.6%) Minimum / Average / Maximum Object : 0.01K / 0.27K / 8.00K OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME 7648 7528 98% 2.00K 478 16 15296K kmalloc-2048 65142 65142 100% 0.19K 1551 42 12408K dentry 17985 17985 100% 0.58K 327 55 10464K inode_cache 7110 7110 100% 1.06K 237 30 7584K xfs_inode 10880 10160 93% 0.50K 170 64 5440K kmalloc-512 30564 30564 100% 0.11K 849 36 3396K sysfs_dir_cache
輸出包括頂部的匯總和slab列表。其中包括對象數量(OBJS)、多少是活動的(ACTIVE)、使用百分比(USE)、對象大小(OBJ SIZE,字節)和緩存大小(CACHE SIZE,字節)。
ps
可以列出包括內存使用統計信息在內的所有進程細節;
%MEM: 主存使用(物理內存、RSS)占總內存的百分比;
RSS:常駐集合大小;
VSZ: 虛擬內存大小;
提示:RSS顯示主存使用,它也包括如系統庫在內的映射共享段,可能會被幾十個進程共享。如果你把RSS列求和,會發現她超過系統內存總和,這是由於重復計算了這部分共享內存。
pmap
[root@localhost ~]# pmap -x 1096 1096: /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock Address Kbytes RSS Dirty Mode Mapping 0000000000400000 11960 3468 0 r-x-- mysqld 00000000011ae000 668 240 172 r---- mysqld 0000000001255000 1028 364 208 rw--- mysqld 0000000001356000 340 312 312 rw--- [ anon ] 0000000001887000 7508 7344 7344 rw--- [ anon ] ...省略部分... 00007ffc659e9000 132 72 72 rw--- [ stack ] 00007ffc65ba1000 8 4 0 r-x-- [ anon ] ffffffffff600000 4 0 0 r-x-- [ anon ] ---------------- ------- ------- ------- total kB 961172 121756 116468
內存優化
首先關於內核優化的相關參數
vm.dirty_background_bytes:默認值為0, 觸發pdflush后台回寫的臟存儲器量;
vm.dirty_background_ratio:默認值10, 觸發pdflush后台回寫臟系統存儲器百分比;
vm.dirty_bytes:默認值為0,觸發一個寫入進程開始回寫的臟存儲器量;
vm.dirty_ratio:默認值為20,觸發一個寫入進程開始回寫的臟系統存儲器比例;
vm.dirty_expire_centisecs:默認值為3000,使用pdflush的臟存儲器最小時間;
vm.dirty_writeback_centisecs:默認值為500,pdflush活躍時間間隔(0為停用);
vm.min_free_kbytes:默認值為 dynamic,設置期望的空閑存儲器量(一些內核自動分配器能消耗它);
vm.overconmmit_memory:默認值為0,0表示利用探索法允許合理的國度分配;1表示一直國度分配;3表示禁止國度分配;
vm.swappiness:默認值為60,相對於頁面高速緩存回收更傾向用交換釋放存儲器的程度;
vm.vfs_cache_pressure:默認值為100,表示回收高速緩存的目錄和inode對象的程度。較低的值會保留更多;0意味着從不回收,容器導致存儲器耗盡的情況;
提示:
vm.dirty_background_bytes和vm.dirty_background_ratio是互斥的,dirty_bytes 和 dirty_ratio 也是如此,僅能設置一個。vm.swappiness參數對性能會產生顯著的影響,建議設置為0;因為應用程序內存能盡可能就地駐留。
最后說明,在現在內核發展過程之中,linux內存頁面已經支持大頁面和超大頁面以及透明大頁面等,可以根據自身環境進行適當的調整。紅帽企業版 Linux 6 采用第二種方法,即使用超大頁面。簡單說,超大頁面是 2MB 和 1GB 大小的內存塊。2MB 使用的頁表可管理多 GB 內存,而 1GB 頁是 TB 內存的最佳選擇。