linux之hugepage
?
參考oracle 數據庫官網提到的關于hugepage的介紹,上面提到:
HugePages is a feature integrated into the Linux kernel 2.6. Enabling HugePages makes it possible for the operating system to support memory pages greater than the default (usually 4 KB). Using very large page sizes can improve system performance by reducing the amount of system resources required to access page table entries. HugePages is useful for both 32-bit and 64-bit configurations. HugePage sizes vary from 2 MB to 256 MB, depending on the kernel version and the hardware architecture. For Oracle Databases, using HugePages reduces the operating system maintenance of page states, and increases Translation Lookaside Buffer (TLB) hit ratio.
翻譯一下就是:
HugePages是集成到Linux內核2.6中的一個特性。啟用HugePages使得操作系統能夠支持大于默認值(通常為4 KB)的內存分頁。使用非常大的頁面大小可以減少訪問頁表項所需的系統資源,從而提高系統性能。HugePages對于32位和64位配置都很有用。大頁面大小從2 MB到256 MB不等,具體取決于內核版本和硬件架構。對于Oracle數據庫,使用HugePages可以減少操作系統對頁面狀態的維護,并提高Translation Lookaside Buffer(旁路轉換緩沖,或稱為頁表緩沖,即TLB。關于TLB的介紹可參考。)的命中率。
本文參考:
https://juejin.cn/post/6844903507594575886
https://zhuanlan.zhihu.com/p/65298260
原文寫的非常好,此篇做筆記用。
?
?
介紹Hugepage首先需要知道什么是虛擬內存。
虛擬內存
我們知道一個進程是與其他進程共享CPU和內存資源的。為了防止進程之間內存泄漏的問題,現代操作系統提供了一種對主存的抽象概念,即是虛擬內存(Virtual Memory)。虛擬內存為每個進程提供了一個一致的、私有的地址空間,它讓每個進程產生了一種自己在獨享主存的錯覺(每個進程擁有一片連續完整的內存空間)。
因為使用虛擬地址可以帶來諸多好處:
既然使用虛擬地址,就涉及到將虛擬地址轉換為物理地址的過程,也即CPU尋址。
CPU尋址
內存通常被組織為一個由M個連續的字節大小的單元組成的數組,每個字節都有一個唯一的物理地址(Physical Address PA),作為到數組的索引。CPU訪問內存最簡單直接的方法就是使用物理地址,這種尋址方式被稱為物理尋址。
現代處理器使用的是一種稱為虛擬尋址(Virtual Addressing)的尋址方式。使用虛擬尋址,CPU需要將虛擬地址翻譯成物理地址,這樣才能訪問到真實的物理內存。它需要MMU(Memory Management Unit)和頁表(page table)的共同參與。
MMU
MMU是處理器/核(processer)中的一個硬件單元,通常每個核有一個MMU。它的功能是將虛擬地址轉換為物理地址。MMU需要借助存放在內存中的頁表(page table)來動態翻譯虛擬地址,該頁表由操作系統管理。
MMU由兩部分組成:TLB(Translation Lookaside Buffer)和table walk unit。
Page Table
page table是每個進程獨有的,是軟件實現的,是存儲在main memory(比如DDR)中的。所謂頁表就是一個存放在物理內存中的數據結構,它記錄了虛擬頁與物理頁的映射關系。
頁表是一個元素為頁表條目(Page Table Entry, PTE)的集合,每個虛擬頁在頁表中一個固定偏移量的位置上都有一個PTE。下面是PTE僅含有一個有效位標記的頁表結構,該有效位代表這個虛擬頁是否被緩存在物理內存中。
虛擬頁VP 0、VP 4、VP 6、VP 7被緩存在物理內存中,虛擬頁VP 2和VP 5被分配在頁表中,但并沒有緩存在物理內存,虛擬頁VP 1和VP 3還沒有被分配。
在進行動態內存分配時,例如malloc()函數或者其他高級語言中的new關鍵字,操作系統會在硬盤中創建或申請一段虛擬內存空間,并更新到頁表(分配一個PTE,使該PTE指向硬盤上這個新創建的虛擬頁)。
頁命中
如下圖所示,MMU根據虛擬地址在頁表中尋址到了PTE 4,該PTE的有效位為1,代表該虛擬頁已經被緩存在物理內存中了,最終MMU得到了PTE中的物理內存地址(指向PP 1)。
缺頁
如下圖所示,MMU根據虛擬地址在頁表中尋址到了PTE 2,該PTE的有效位為0,代表該虛擬頁并沒有被緩存在物理內存中。虛擬頁沒有被緩存在物理內存中(緩存未命中)被稱為缺頁。
當CPU遇見缺頁時會觸發一個缺頁異常,缺頁異常將控制權轉向操作系統內核,然后調用內核中的缺頁異常處理程序,該程序會選擇一個犧牲頁,如果犧牲頁已被修改過,內核會先將它復制回硬盤(采用寫回機制而不是直寫也是為了盡量減少對硬盤的訪問次數),然后再把該虛擬頁覆蓋到犧牲頁的位置,并且更新PTE。
當缺頁異常處理程序返回時,它會重新啟動導致缺頁的指令,該指令會把導致缺頁的虛擬地址重新發送給MMU。由于現在已經成功處理了缺頁異常,所以最終結果是頁命中,并得到物理地址。
這種在硬盤和內存之間傳送頁的行為稱為頁面調度(paging):頁從硬盤換入內存和從內存換出到硬盤。當缺頁異常發生時,才將頁面換入到內存的策略稱為按需頁面調度(demand paging),所有現代操作系統基本都使用的是按需頁面調度的策略。
虛擬內存跟CPU高速緩存(或其他使用緩存的技術)一樣依賴于局部性原則。雖然處理缺頁消耗的性能很多(畢竟還是要從硬盤中讀取),而且程序在運行過程中引用的不同虛擬頁的總數可能會超出物理內存的大小,但是局部性原則保證了在任意時刻,程序將趨向于在一個較小的活動頁面(active page)集合上工作,這個集合被稱為工作集(working set)。根據空間局部性原則(一個被訪問過的內存地址以及其周邊的內存地址都會有很大幾率被再次訪問)與時間局部性原則(一個被訪問過的內存地址在之后會有很大幾率被再次訪問),只要將工作集緩存在物理內存中,接下來的地址翻譯請求很大幾率都在其中,從而減少了額外的硬盤流量。
如果一個程序沒有良好的局部性,將會使工作集的大小不斷膨脹,直至超過物理內存的大小,這時程序會產生一種叫做抖動(thrashing)的狀態,頁面會不斷地換入換出,如此多次的讀寫硬盤開銷,性能自然會十分“恐怖”。所以,想要編寫出性能高效的程序,首先要保證程序的時間局部性與空間局部性。
多級頁表
上面討論的只是單頁表,但在實際的環境中虛擬空間地址都是很大的(一個32位系統的地址空間有2^32 = 4GB,更別說64位系統了)。在這種情況下,使用一個單頁表明顯是效率低下的,而且非常占內存空間。
常用方法是使用層次結構的頁表。
假設我們的環境為一個32位的虛擬地址空間,它有如下形式:
-
虛擬地址空間被分為4KB的頁,每個PTE都是4字節。
-
內存的前2K個頁面分配給了代碼和數據。
-
之后的6K個頁面還未被分配。
-
再接下來的1023個頁面也未分配,其后的1個頁面分配給了用戶棧。
下圖是為該虛擬地址空間構造的二級頁表層次結構(真實情況中多為四級或更多),一級頁表(1024個PTE正好覆蓋4GB的虛擬地址空間,同時每個PTE只有4字節,這樣一級頁表與二級頁表的大小也正好與一個頁面的大小一致都為4KB)的每個PTE負責映射虛擬地址空間中一個4MB的片(chunk),每一片都由1024個連續的頁面組成。二級頁表中的每個PTE負責映射一個4KB的虛擬內存頁面。
這個結構看起來很像是一個B-Tree,這種層次結構有效的減緩了內存要求:
-
如果一個一級頁表的一個PTE是空的,那么相應的二級頁表也不會存在。這代表一種巨大的潛在節約(對于一個普通的程序來說,虛擬地址空間的大部分都會是未分配的)。
-
只有一級頁表才總是需要緩存在內存中的,這樣虛擬內存系統就可以在需要時創建、頁面調入或調出二級頁表(只有經常使用的二級頁表才會被緩存在內存中),這就減少了內存的壓力。
TLB
表是被緩存在內存中的,盡管內存的速度相對于硬盤來說已經非常快了,但與CPU還是有所差距。為了防止每次地址翻譯操作都需要去訪問內存,CPU使用了高速緩存與TLB來緩存PTE。CPU會首先在TLB中查找,因為在TLB中找起來很快。TLB之所以快,一是因為它含有的entries的數目較少,二是TLB是集成進CPU的,它幾乎可以按照CPU的速度運行。
TLB(Translation Lookaside Buffer, TLB)旁路緩沖器,或叫做頁表緩存,它是MMU中的一個緩沖區。
TLB命中:
-
第一步,CPU將一個虛擬地址交給MMU進行地址翻譯。
-
第二步和第三步,MMU通過TLB取得相應的PTE。
-
第四步,MMU通過PTE翻譯出物理地址并將它發送給高速緩存/內存。
-
第五步,高速緩存返回數據到CPU(如果緩存命中的話,否則還需要訪問內存)。
TLB未命中:
當TLB未命中時,MMU必須從高速緩存/內存中取出相應的PTE,并將新取得的PTE存放到TLB(如果TLB已滿會覆蓋一個已經存在的PTE)。如下圖:
綜上,整個cpu尋址的過程可以用下圖表示:
?
如果在TLB中找到了含有該虛擬地址的entry(TLB hit),則可從該entry【1】中直接獲取對應的物理地址,否則就不幸地TLB miss了,就得去查找當前進程的page table。這個時候,組成MMU的另一個部分table walk unit就被召喚出來了,這里面的table就是page table。
如果在page table中找到了該虛擬地址對應的entry的p(present)位是1,說明該虛擬地址對應的物理頁面當前駐留在內存中,也就是page table hit。找到了還沒完,接下來還有兩件事要做:
如果該虛擬地址對應的entry的p位是0,就會觸發page fault(缺頁中斷),可能有這幾種情況:
如果這個虛擬地址在進程的page table中根本不存在,說明這個虛擬地址不在該進程的地址空間中,這時也會觸發segmantation fault。
HugePage
上面中提到使用多級頁表的方式對于減少頁表自身占用的內存空間確實是非常有效的。然而,為此付出的代價就是增加了地址轉換過程中對內存的訪問次數,進而增加了轉換時間。那在除了前面介紹的TLB之外,還有哪些可以減少內存訪問次數,加快地址轉換的方法呢?HugePage即可以。
而HugePage它是使用較大的內存頁來代替默認的4k大小,這就意味相同的物理內存,內存頁的數量會更少,所以需要的page table(頁表條目也會變少),同樣TLB的條目數也會變少。
好處是:
節約了頁表所占用的內存大小,并且地址轉換變少。所以缺頁中斷變少,TLBmiss變少。從而提高了內存訪問性能、TLB命中率,從整體上提高了系統的效率 。
另外,由于地址轉換所需的信息一般保存在CPU的緩存中,huge page的使用讓地址轉換信息減少,從而減少了CPU緩存的使用,減輕了CPU緩存的壓力,讓CPU緩存能更多地用于應用程序的數據緩存,也能夠在整體上提升系統的性能。
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的linux之hugepage的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单好用的安卓程序开发平台E4A
- 下一篇: 基于ssm高校共享单车管理系统 (源代码