大頁面的優點和缺點

大頁面的優點和缺點

為課程學生準備的文章翻譯 “行政人員 Linux».

之前我討論過如何檢查和啟用 Hugepages 的使用。 Linux.
只有當您確實有地方使用 Hugepages 時,本文才會有用。我見過很多人,他們被 Hugepages 能夠神奇地提高生產力的前景所迷惑。然而,大分頁是一個複雜的主題,如果使用不當,可能會降低效能。

第一部分:檢查是否已啟用大頁模式 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 是萬能藥的人難以理解,因此我將犧牲精確性來換取簡單性。值得記住的是,許多主題確實很複雜,因此大大簡化了。

請注意,我們討論的是運行在 64 位元 x86 系統上的系統。 Linux我只是假設系統支援透明大頁(因為不替換大頁並非缺點),這在幾乎所有現代環境中都是如此。 Linux.

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

虛擬內存

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

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

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

  • 生產力(出於各種原因);
  • 程式隔離,意味著沒有程式可以讀取另一個程式的記憶體。

什麼是頁面?

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

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

該過程對於串流來說是透明的,這意味著它不一定直接從硬碟/SSD 讀取。普通頁面的大小為4096位元組。大頁面大小為 2 兆位元組。

轉換後備緩衝區 (TLB)

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

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

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

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

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

大頁面來幫忙

那我們可以做些什麼來避免 TLB 溢出呢? (我們假設程式仍然需要相同數量的記憶體。)

這就是 Hugepages 的用武之地。以前只需要一個 TLB 條目就可以指向 4096 個位元組,而現在一個 TLB 條目可以指向高達 2 MB 的空間。假設 TLB 有 512 個條目,這裡無需 Hugepages 我們就可以映射:

4096 b⋅512=2 MB

那麼我們如何將它們與以下內容進行比較:

2 MB⋅512=1 GB

這就是 Hugepages 如此出色的原因。他們無需付出太多努力就能提高生產力。但這裡有一些重要的警告。

大頁面的替代

核心自動追蹤每個記憶體頁的使用頻率。如果實體記憶體(RAM)不足,核心會將不太重要(不常用)的頁面移至硬碟,以便為更重要的頁面釋放一些 RAM。
基本上,Hugepages 也同樣如此。但是,核心只能交換整個頁面,而不能交換單一位元組。

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

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

在這種情況下,核心必須從硬碟/SSD 中替換(讀取)多達 2 兆位元組的資訊才能讀取一個位元組。對於普通頁面,只需要從HDD/SSD讀取4096位元組。

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

另一方面,如果您需要順序訪問大量內存,大頁面將會提高您的效能。但是,您需要自己測試一下(而不是在抽象的軟體範例上),看看哪種方法運行得更快。

記憶體分配

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

char* mymemory = malloc(30);

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

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

同時,所有事情的發生你都沒有註意到,所以為什麼要關心呢?因為這是一個挑戰 free() 並不意味著 記憶體必須立即返回給作業系統.

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

請注意,記憶體碎片是一個非常複雜的主題,即使對程式進行微小的更改也會對其產生重大影響。在大多數情況下,程式不會造成嚴重的記憶體碎片,但您應該意識到,如果碎片是堆中某些區域的問題,那麼大頁面可能會使情況變得更糟。

選擇性使用大頁面

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

幸運的是,你可以使用 madvise()僅為有用的記憶體區域啟用大頁面調度。

首先,檢查 hugepages 是否在 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

為具有 DDoS 保護、VPS VDS 服務器的站點購買可靠的主機 🔥 購買具備 DDoS 防護的可靠網站寄存服務,包括 VPS 和 VDS 伺服器 | ProHoster