如何使用記憶體相同頁合併特性

2021-12-30 10:13:59 字數 2862 閱讀 4005

ksm是乙個去重以節約記憶體的特性,為 config_ksm=y 所使能,自linux kernel的2.6.32版本加入。它的實現在 mm/ksm.c,

ksm daemon 叫做ksmd,它定期掃瞄已經註冊的使用者空間記憶體,尋找有相同內容的記憶體頁,這些記憶體頁可以被一頁寫保護(write-protected)的記憶體頁所替代(如果將來有程序試圖更新頁的內容,就會自動拷貝出來然後進行更新)。

ksm以前是被開發出來和kvm一起使用的(當時稱之為kernel shared memory),通過共享多個虛擬機器的相同的資料來達到固定物理記憶體可以執行更多虛擬機器的目的。但是這個特性其實對任何會產生多個具有相同資料的例項的應用都是有用的。

ksm只合併匿名(私有)記憶體頁,而不會合併頁面快取(檔案)的記憶體頁。ksm所合併的記憶體頁原先是被鎖定在核心空間的,但現在可以像其他記憶體空間的頁面一樣被交換出來(但是當再被交換回去的時候,共享就被打破了;ksmd會再重新發現這些記憶體頁然後再重新合併)。

ksm只會操作這樣的位址空間:乙個應用程式通過系統呼叫 madvise(2)

int madvise(addr, length, madv_mergeable)

來建議作為合併的候選頁。

應用程式可以呼叫

int madvise(addr, length, madv_unmergeable)

來取消合併建議以恢復為不共享的記憶體頁。注意:這個取消合併的系統呼叫可能突然地要求許多記憶體,甚至超過可用的記憶體量 -- 所以可能會以 eagain 錯誤碼失敗,但更可能是喚醒 out-of-memory killer.

如果ksm並沒有被配置到正在執行的核心中(譯註:config_ksm=y 是核心編譯配置),madvise madv_mergeable 和 madv_unmergeable 就會以 einval 而失敗。如果正在執行的核心是以 config_ksm=y 構建的,這些呼叫一般會成功:即使ksm daemon現在並沒有在執行,madv_mergeable 仍然在以後ksm daemon啟動的時候註冊記憶體範圍;即使該記憶體範圍不包含任何ksm能夠合併的記憶體,也不會出錯;即使 madv_unmergeable 被應用在乙個從未使用過 madv_mergeable 的記憶體範圍,也不會出錯。

和其他的madvise系統呼叫一樣,它們是用於使用者位址空間的對映區域的(for use on mapped areas of the user address space): 如果指定範圍內包含了 unmapped gaps (即使在其間的mapped areas上可以工作),就會報告enomem錯誤;如果內部的資料結構沒有足夠的記憶體,就會報錯 eagain.

應用程式使用 madv_mergeable 時應該是審慎的,嚴格限制將其用於可能會有收益的地方。ksm的掃瞄可能會耗費許多計算資源:一些安裝程式會因此而禁用ksm.

ksm daemon被位於 /sys/kernel/mm/ksm/ 目錄下的 sysfs 檔案所控制,這些檔案對所有使用者都可讀,但只有root才具有修改許可權:

pages_to_san

- 在ksmd休眠(sleep)之前,有多少頁面要掃瞄(譯註:即每次掃瞄多少頁面,然後就睡眠去),比如,"echo 100 > /sys/kernel/mm/ksm/pages_to_scan", 預設值: 100 (為演示的目的) (譯註:可能這個值有點小,因為是演示目的)

sleep_millisecs

- 在下一次掃瞄之前,ksmd會睡眠多久(譯註:即每次sleep多久),比如,"echo 20 > /sys/kernel/mm/ksm/sleep_millisecs", 預設值:20(為演示目的)(譯註:可能這個值有點小,只sleep 20ms會使得cpu佔用率較高,在有些系統上達5%左右)

merge_across_nodes

- 如果頁面來自於其他numa節點,此引數用於指定這些頁面是否能夠被合併。

當設定成0,ksm只會合併物理位置上位於同乙個numa節點上的記憶體頁。這為訪問共享記憶體頁帶來了更低的延遲。對於有許多節點的系統,有顯著的numa距離,它們比較能夠從「設定為0」這個低延遲設定中獲益。對於需要最小化記憶體使用的更小的系統,則設定為1更容易獲益(預設就是設定為1)。你可能希望對你的系統測試一下這2種設定,看看哪一種更合適。本設定只有在系統中沒有ksm共享頁的時候才能被修改:首先,將"run"設定為2以unmerge所有的頁面,然後在改變merge_across_nodes設定之後,將"run"設定為1,即在修改merge_across_nodes之後重新合併。

預設值:1

run- 設為 0 是讓ksmd停止掃面但保持已經合併的頁面,

設為 1 是執行 ksmd 使其工作,比如 "echo 1 > /sys/kernel/mm/ksm/run",

設為 2 是停止ksmd,並且unmerge所有已經合併的頁面,但保持可合併區域的註冊以便下次run的時候使用。

預設值:0(必須被改為1才能啟用ksm,除非 config_sysfs 是 disabled狀態)

ksm 和 madv_mergeable 的效果也被顯示在目錄 /sys/kernel/mm/ksm/:

pages_shared - 多少共享頁面正在被使用

pages_sharing - 多少單位在分享這些共享頁,即,節省了多少記憶體頁

pages_unshared - 多少記憶體頁是獨一無二的,但卻是被反覆檢查是否能合併的

pages_volatile - 多少記憶體頁改變太快以致不能在樹中儲存

full_scans - 發生了多少次所有頁面都被掃瞄了

pages_sharing 除以 pages_shared 的結果如果比較大,則說明共享很多;但 pages_unshared 除以 pages_shared 的結果如果很大,則說明浪費了很多運算能力來進行掃瞄。pages_volatile 高是有幾種可能性,但比較大的概率仍是 madvise madv_mergeable 使用得並不能發揮效力。

(完)

如何合併兩個結構相同的DataTable

今天遇到了乙個情況,就是從一張資料表中讀取幾個符合條件1的客戶的資訊,然後再讀取幾個符合條件2的客戶的資訊,最後顯示出來.因為前後兩次資料的客戶資訊的結構是完全相同的,所以乾脆合併成乙個datatable再賦值給gridview好了.寫了個函式.合併兩個相同的datatable,返回合併後的結果 p...

使用VBA實現Excel合併相同內容的相鄰單元格

寫演算法的資料分析時生成了csv檔案,為了方便檢視需要對部分單元格進行合併。原始的csv檔案用excel開啟有大量如下形式的子表 而我希望處理之後變成如下格式 在網上搜尋了很久,大多只能對某一列進行操作,而我需要對整個 的行列都進行這個操作。除此之外,因為是資料分析的 我還希望只對非數字開頭的單元格...

如何正確使用記憶體

如何正確使用記憶體 對於初學者來說,記憶體是個神秘的空間。程式的絕大部分錯誤,也是在於記憶體的使用不當造成的,而且這些錯誤有些都是隱藏很深的。所以,如何掌握記憶體的使用,通曉系統對記憶體的管理手段,將是軟體成功的乙個非常關鍵的因素。首先我們要了解記憶體的分配方式。一般來說,記憶體的分配方式有三種 1...