大頁面的優點和缺點

大頁面的優點和缺點

為課程學生準備的文章翻譯 《Linux 管理員》.

之前,我討論瞭如何在 Linux 上測試和啟用 Hugepages。
只有當您確實有地方可以使用 Hugepages 時,本文才有用。 我遇到過很多人,他們被大頁將神奇地提高生產力的前景所愚弄。 然而,大分頁是一個複雜的主題,如果使用不當可能會降低效能。

第 1 部分:驗證 Linux 上是否啟用了大頁(原始 這裡)

問題:
您需要檢查系統上是否啟用了 HugePages。

解決方案:
這很簡單:

cat /sys/kernel/mm/transparent_hugepage/enabled

你會得到這樣的東西:

always [madvise] never

您將看到可用選項的清單(總是,瘋狂,從不),當前活動選項將括在括號中(預設情況下 瘋狂的).

瘋狂的 意思是 transparent hugepages 僅對顯式請求大頁的記憶體區域啟用 瘋狂的維斯(2).

時刻 意思是 transparent hugepages 始終對所有進程啟用。 這通常會提高效能,但如果您的用例中有許多進程消耗少量內存,則整體內存負載可能會急劇增加。

決不 意思是 transparent hugepages 即使使用 madvise 請求,也不會包含在內。 如需了解更多信息,請聯繫 文件 Linux 核心。

如何更改預設值

選項1: 直接改 sysfs (重啟後參數將恢復預設值):

echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled

選項2:透過使用修改後的配置重新編譯核心來更改系統預設值(僅在使用自訂核心時建議使用此選項):

  • 若要設定始終默認,請使用:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • 若要將 madvise 設定為預設值,請使用:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

第 2 部分:HugePages 的優點和缺點

我們將嘗試選擇性地解釋使用 Hugepages 的優點、缺點和可能的陷阱。 由於技術上複雜且迂腐的文章對於那些被欺騙認為 Hugepages 是萬能藥的人來說可能很難理解,因此我會為了簡單性而犧牲準確性。 值得記住的是,許多主題確實很複雜,因此被大大簡化了。

請注意,我們正在談論運行 Linux 的 64 位元 x86 系統,我只是假設該系統支援透明大頁(因為大頁不被覆蓋並不是一個缺點),就像幾乎所有現代 Linux 中的情況一樣。

我將在下面的連結中附上更多技術說明。

虛擬內存

如果您是 C++ 程式設計師,您就會知道記憶體中的物件具有特定的位址(指標值)。

然而,這些位址不一定反映記憶體中的實體位址(RAM 位址)。 它們代表虛擬記憶體中的位址。 處理器有一個特殊的MMU(記憶體管理單元)模組,可以幫助核心將虛擬記憶體映射到實體位置。

這種方法有很多優點,但最重要的是:

  • 性能(出於各種原因);
  • 程式隔離,即任何程式都不能讀取另一個程式的記憶體。

什麼是頁面?

虛擬記憶體分為頁。 每個單獨的頁面都指向特定的實體內存,它可以指向 RAM 中的一個區域,也可以指向分配給實體設備(例如視訊卡)的位址。

您處理的大多數頁面要么指向 RAM,要么被交換,這意味著它們儲存在您的硬碟或 SSD 上。 核心管理每個頁面的實體佈局。 如果造訪欺騙頁面,核心會停止嘗試存取記憶體的線程,將該頁面從硬碟/SSD 讀取到 RAM,然後繼續執行該線程。

此過程是流透明的,這意味著它不一定直接從 HDD/SSD 讀取。 普通頁的大小為 4096 位元組。 大頁大小為 2 兆位元組。

翻譯關聯緩衝區 (TLB)

當程式存取記憶體頁時,CPU必須知道從哪個實體頁讀取資料(即有虛擬位址對映)。

核心有一個資料結構(頁表),其中包含有關正在使用的頁面的所有資訊。 使用此資料結構,您可以將虛擬位址對應到實體位址。

然而,頁表相當複雜且緩慢,因此我們根本無法在進程每次存取記憶體時分析整個資料結構。

幸運的是,我們的處理器有一個 TLB,可以快取虛擬位址和實體位址之間的對應。 這意味著,雖然我們需要在第一次存取嘗試時解析頁表,但所有後續對該頁的存取都可以在 TLB 中處理,從而實現快速操作。

因為它是作為實體設備實現的(這首先使其速度很快),所以它的容量是有限的。 因此,如果您想存取更多頁面,TLB 將無法儲存所有頁面的映射,從而導致程式運行速度變慢。

大頁來拯救

那我們該如何避免TLB溢出呢? (我們假設程式仍然需要相同數量的記憶體)。

這就是大頁發揮作用的地方。 現在,一個 TLB 條目可以指向高達 4096 兆位元組,而不是只需要一個 TLB 條目的 2 位元組。 假設 TLB 有 512 個條目,這裡沒有大頁我們可以配對:

4096 b⋅512=2 MB

那我們如何與他們進行比較:

2 MB⋅512=1 GB

這就是 Hugepages 如此出色的原因。 他們可以毫不費力地提高生產力。 但這裡有一些重要的警告。

大頁欺騙

核心自動監視每個記憶體頁的使用頻率。 如果沒有足夠的實體記憶體 (RAM),核心會將不太重要(不經常使用)的頁面移至硬碟,以便為更重要的頁面釋放一些 RAM。
原則上,這同樣適用於大頁。 但是,核心只能交換整個頁面,而不能交換單一位元組。

假設我們有一個這樣的程式:

char* mymemory = malloc(2*1024*1024); // Возьмем это за одну Hugepage!
// Заполним mymemory какими-либо данными
// Сделаем много других вещей,
// которые приведут к подмене страницы mymemory
// ...
// Запросим доступ только к первому байту
putchar(mymemory[0]); 

在這種情況下,核心將需要從硬碟/SSD 中替換(讀取)多達 2 MB 的訊息,只是為了讓您讀取一個位元組。 對於常規頁面,只需要從硬碟/SSD 讀取 4096 位元組。

因此,如果覆蓋hugepage,只有在需要存取整個頁面時讀取速度才會更快。 這意味著,如果您嘗試隨機存取記憶體的不同部分並且僅讀取數千字節,則應該使用常規頁面,而不必擔心其他任何事情。

另一方面,如果您需要順序訪問大部分內存,大頁面將提高您的效能。 但是,您需要自己測試它(而不是使用抽象軟體)並查看哪種效果更快。

記憶體分配

如果您編寫 C,您知道可以使用以下命令從堆中請求任意小(或幾乎任意大)的內存量 malloc()。 假設您需要 30 位元組記憶體:

char* mymemory = malloc(30);

對於程式設計師來說,您可能會從作業系統「請求」30 位元組記憶體並傳回指向某個虛擬記憶體的指標。 但實際上 malloc () 只是一個從函數內部呼叫的 C 函數 brk和sbrk 從作業系統請求或釋放記憶體。

然而,為每次分配請求越來越多的記憶體是低效的; 很可能某些記憶體段已經被釋放 (free()),我們可以重複使用它。 malloc() 實作了相當複雜的演算法來重複使用釋放的記憶體。

同時,一切都在你不經意間發生,所以為什麼要擔心呢? 但因為挑戰 free() 並不意味著 記憶體必須立即返回給作業系統.

存在記憶體碎片這樣的事情。 在極端情況下,存在僅使用幾個位元組的堆段,而其間的所有內容都已被釋放 (free()).

請注意,記憶體碎片是一個極其複雜的主題,即使對程式進行微小的更改也會產生重大影響。 大多數情況下,程式不會造成明顯的記憶體碎片,但你應該意識到,如果堆的某些區域有碎片問題,hugepages 會讓情況變得更糟。

選擇性使用大頁

閱讀本文後,您已經確定程式的哪些部分可以從使用大頁中受益,哪些部分不能。 那麼是否應該啟用大頁呢?

幸運的是你可以使用 madvise()僅對那些有用的記憶體區域啟用大分頁。

首先,使用以下命令檢查大頁面是否在 madvise() 模式下執行 路線 在文章的開頭。

然後,使用 madvise()告訴內核到底在哪裡使用大頁面。

#include <sys/mman.h>
// Аллоцируйте большое количество памяти, которую будете использовать
size_t size = 256*1024*1024;
char* mymemory = malloc(size);
// Просто включите hugepages…
madvise(mymemory, size, MADV_HUGEPAGE);
// … и задайте следующее
madvise(mymemory, size, MADV_HUGEPAGE | MADV_SEQUENTIAL)

請注意,此方法只是向核心提供有關如何管理記憶體的建議。 這並不意味著核心將自動對給定記憶體使用大頁。

參考文檔 (線上說明頁)madvise了解有關記憶體管理的更多信息 madvise(),這個主題的學習曲線非常陡峭。 因此,如果您打算真正擅長於此,請準備好幾週的閱讀和測試,然後才能期待任何積極的結果。

讀什麼?

有一個問題? 寫在評論裡!

來源: www.habr.com

添加評論