坑爹的大頁內存


內存是計算機中的珍貴的稀有資源,所以為了精細管理,內存管理非常復雜的,一台計算機會同時運行很多應用,為了防止這些應用程序爭搶內存,內存的管理是通過操作系統來管理的,操作系統為了方便管理內存,也為了降低應用使用內存的復雜性,引入了虛擬內存的概念( 還是那句話,解決不了的問題引入一個中間層)。

一 虛擬內存

虛擬內存,可以看成內存和磁盤的抽象,通過中斷,地址翻譯,內存,磁盤文件,內核軟件等交互,為每個應用程序均提供一個私有的大的地址空間。

在32位系統上,虛擬內存可以訪問的存儲空間為:232; 64位系統中虛擬存儲地址空間范圍不是264,而是一般為:248,以為現在還用不了這么大的空間,可以通過命令:

[root@izbp14xswj2tx6qgnz9dllz ~]# cat /proc/cpuinfo 
......
address sizes : 46 bits physical, 48 bits virtual
power management:

結果中:

address sizes : 46 bits physical, 48 bits virtual

表示物理地址為:46位,虛擬地址為48位。

這么大的空間是如何划分的那: linux下32位虛擬地址的空間划分

虛擬內存采用頁為單位進行存儲管理的,典型的頁面大小為4KB或1MB,linux下可以通過getconf命令查看。頁面大小順便說一句,有些特殊的場景喜歡設置超級大頁,比如在DPDK這種高性能網絡處理庫中,常設置大頁為1GB,目的是為了減少頁表的條目,可以讓頁表完全保存的高速緩存中,提升內存分配效率。

虛擬內存畢竟是虛的,在使用的時候系統會判斷對應此虛擬內存頁是否有映射的物理內存,如果沒有對應的物理內存頁,就會發生缺頁中斷,操作系統就會給這個虛擬內存頁分配真正的物理內存,建立映射關系;如果現在物理內存也使用緊張,操作系統就會將不活躍的頁換出存到磁盤的swap空間,將物理內存頁釋放出來,以供使用;如果下次換出的頁面需要使用了,又會產生缺頁中斷,被換入到物理內存中,就這樣來回倒騰,由於應用具有局部性,所以一般情況下,應用程序只在少量頁面上工作,效率並不低。

[root@localhost ~]# cat /proc/swaps
Filename                Type        Size    Used    Priority
/dev/dm-1                               partition   2097148 0   -1
[root@localhost ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           2.8G        155M        2.4G        9.8M        234M        2.4G
Swap:          2.0G          0B        2.0G
[root@localhost ~]# swapon -s
文件名             類型      大小  已用  權限
/dev/dm-1                               partition   2097148 0   -1

二 地址翻譯

剛才說了,我們應用使用的是虛擬內存,真正使用的時候才會通過操作系統,MMU(內存管理單元)和存在內存中的頁表結合來完成虛擬地址和物理地址的翻譯工作。頁表將虛擬地址映射為物理地址,如下圖: 虛擬內存和物理內存轉換

實際情況要更復雜,比如分了多級頁表,多級頁表可以減少內存的使用,比如在x86的32位地址上通過二級頁表完成地址的翻譯。

這些頁表是保存在內存中的,如果每次都要這么翻譯,內存訪問的性能肯定是受到一定影響的,數據都可以緩存,頁表頁同樣可以進一步緩存放在SRAM中,MMU中有關於頁表的緩存,小的緩存稱為TLB(后備緩沖器),加入TLB后,翻譯就如下圖: 引入TLB

好了問題來了,TLB是一個小的緩存,保存的映射頁表項畢竟是有限的。如果4GB虛擬內存空間,每個頁面大小位4K,那就有220個頁,如果需要4個字節來標識一個頁表項的數據的話那么頁表的大小就為4B*1M即4MB大小的空間。

頁表大小= 頁表項個數*頁表項大小

按照上圖,如果我們的整個頁表都可以保存到TLB中,將提升內存的訪問速度,從幾十到幾百個時鍾周期,降低到1到2個時鍾周期,頁表項的大小一般是固定不變的,因為TLB的大小受限,所以我們只能想辦法減少頁表項的個數,頁表項的個數= 總內存/一個內存頁大小,顯然,如果我們增加內存頁的大小,比如我們設置內存頁大小為1GB,那么4GB的內存,只需要4個頁表項,很容易將整個頁表都保存在內存中,從而提升內存的訪問速度。

三 大頁內存

上面提到,我們為了提升內存訪問速度,我們對於耗費很大的應用比如Oracle等,可以采用大頁內存方式,如果程序本身使用的內存很少,采用大頁內存效果不明顯,還浪費內存。

3.1 查看是否支持

Linux系統采用hugetlbfs 的特殊文件系統來加入對2MB和1GB的大頁內存的支持,為了配置,先查看cpu是否支持:

 cat  /proc/cpuinfo |grep --color pse
 cat  /proc/cpuinfo |grep --color pdpe1gb

查看內核是否支持:

 grep  -i hugetlb /boot/config-4.18.0-193.el8.x86_64 
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
CONFIG_CGROUP_HUGETLB=y
# 以下兩種都為y則標識支持
CONFIG_HUGETLBFS=y 
CONFIG_HUGETLB_PAGE=y

cpu的功能列表中含有pse標識支持2MB的內存大頁,含有pdpe1gb支持1GB的內存大頁。

3.2 查看大頁內存使用情況

grep Huge /proc/meminfo
AnonHugePages:   4089856 kB
ShmemHugePages:        0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB

這里面說明,一個大頁為:2MB(Hugepagesize: 2048 kB)總共有的內存大頁數量為:HugePages_Total: 0 NUMA架構的查看:

[root@localhost ~]# cat /sys/devices/system/node/node*/meminfo|fgrep Huge
Node 0 AnonHugePages:    153600 kB
Node 0 HugePages_Total:     0
Node 0 HugePages_Free:      0
Node 0 HugePages_Surp:      0
Node 1 AnonHugePages:     30720 kB
Node 1 HugePages_Total:     0
Node 1 HugePages_Free:      0
Node 1 HugePages_Surp:      0

可以看到這個NUMA機器上並沒有分配大頁內存:

HugePages_Total: 0

3.3 分配大頁內存

如果分配2MB的大頁內存比較簡單,可以通過命令預留:

echo 1024> /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

預留1024個2MB的大頁即預留2GB的大頁內存。

如果是NUMA架構,在每個node節點上預留:

echo 1024> /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
echo 1024> /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages

如果要分配超過1GB的大頁內存,需要在linux的啟動項中設置和掛載。 1) 安裝

yum install libhugetlbfs

2) 分配 更改啟動文件,添加:

transparent_hugepage=never default_hugepagesz=1G hugepagesz=1G hugepages=4

分配4個大頁內存,每個為1G,在centos6中是修改

/etc/grub.conf

centos7是修改/etc/grub2.cfg文件. 3) mount 將大頁內存映射到空目錄:

mkdir    /mnt/myhuge
mount -t hugetlbfs nodev /mnt/myhuge

如果要開機自動設置:

vim /etc/fstab
nodev /mnt/myhuge hugetlbfs pagesize=1GB 0 0

像DPDK等有專門的設置工具,開機的時候立刻設置防止內存不夠,大頁內存需要連續的空間。

3.4 程序使用

#這個是看資料查的,並沒有實踐過
HUGETLB_MORECORE=yes   LD_PRELOAD=libhugetlbfs.so     ./your_program

四 大頁優缺點

優點: 1) 大頁內存TLB miss 很少,缺頁中斷也很少,對於內存的訪問性能更好,對於占用大量內存的程序,性能提升比較明顯,可以提升達到50%左右。 2) 大頁內存的內存頁不會swap到磁盤上。

缺點: 1) 必須使用特定的方式使用,比如采用mmap映射或者通過上面方式指定。 2) 程序使用內存小,卻申請了大頁內存,會造成內存浪費,因為內存分配最小單位是頁。

五 大頁內存引起的杯具

說了半天,還沒有說到大頁內存引起了什么杯具那,是這樣的,在一台機器上,內存本來就很小,只有4GB內存,查看程序占用內存一直沒多少,當時剩余內存也很少就很奇怪。 分析下內存分配:

# cat /proc/meminfo|grep Huge
HugePages_Total:    1035
HugePages_Free:     1033
HugePages_Rsvd:       62
HugePages_Surp:        0
Hugepagesize:       2048 kB

更好的工具是用atop查看,發現大頁內存占用了了高達2GB的內存,卻沒怎么使用。

解決辦法

#禁用大頁緩存
vi /etc/sysctl.conf

vm.nr_hugepages = 0
vm.nr_hugepages_mempolicy = 0

# 生效
sysctl -p

立竿見影的效果,一下釋放了2GB的內存,這可是占系統的內存一半啊,所以大頁內存是否使用,還要斟酌,不然白白浪費了大量內存。

如果程序內存占用大,TLB的miss又很多的情況下,可以使用,具體如何查看TLB的miss多那,可以通過perf工具來進行分析:

perf record -e dTLB-loads -e faults -p pid
perf report

六 詩詞欣賞

 竹里館  - - [王維]

獨坐幽篁里,彈琴復長嘯。
深林人不知,明月來相照。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM