主頁 > 作業系統 > Linux Cgroup v1(中文翻譯)(6):Memory Resource Controller

Linux Cgroup v1(中文翻譯)(6):Memory Resource Controller

2022-06-16 15:59:24 作業系統

Memory Resource Controller

記憶體資源控制器


目錄
  • Memory Resource Controller
  • 記憶體資源控制器
  • 記憶體控制器的優點和目的
  • 1. 歷史
  • 2. 記憶體控制
    • 2.1. 設計
    • 2.2. 統計
      • 2.2.1 統計詳情
    • 2.3 共享頁面統計
    • 2.4 交換記憶體擴展(Swap Extension)
    • 2.5 回收Reclaim
    • 2.6 鎖Locking
    • 2.7 內核記憶體擴展(CONFIG_MEMCG_KMEM)
      • 2.7.1 當前統計的內核記憶體資源
      • 2.7.2 常用用例
  • 3. 用戶介面
  • 4. 測驗
    • 4.1 疑難解答
    • 4.2 任務遷移
    • 4.3 移除控制組
  • 5. 其他介面
    • 5.1 force_empty
    • 5.2 stat檔案
    • 5.3 swappiness
    • 5.4 failcnt
    • 5.5 usage_in_bytes
    • 5.6 numa_stat
  • 6. 分層支持
    • 6.1 分層統計和回收
  • 7. 軟限制Soft limits
    • 7.1 介面
  • 8. 任務遷移時的移動記賬
    • 8.1 介面
    • 8.2 可被移動的記賬型別
    • 8.3 TODO
  • 9. 記憶體閾值
  • 10. OOM Control
  • 11. 記憶體壓力
  • 12. TODO
  • 總結
  • References


注意:
這個檔案完完全全地過時了,需要整個地重寫,但它還是包含了有用的資訊,所以我們仍舊把它保留在這里,但是如果你需要深入理解的話,需要確保核對過當前的代碼,

注意:
記憶體資源控制器在本檔案中指的是記憶體控制器,不要混淆了這里記憶體控制器和硬體中使用的記憶體控制器,

(給編輯者)在本檔案中:
當我們提到記憶體控制器的控制組(cgroupfs目錄)時,我們稱之為“記憶體控制組”(memory cgroup),當你查看git-log和源代碼時,你會看到補丁的抬頭和功能名稱傾向于使用"memcg",在本檔案中,我們避免使用它,

記憶體控制器的優點和目的

記憶體控制器把一組任務的記憶體從系統中其他任務的記憶體中隔離出來,LWN[12]中的文章提到了記憶體控制器的一些作用,記憶體控制器能用來:

  • 分離應用程式,或者一組記憶體饑餓的應用程式能夠被分離和限制到較少量的記憶體上,
  • 創建記憶體數量有限的控制組,也可選擇啟動時帶有mem=xxx選項,
  • 虛擬化方案能控制分配給虛擬機實體的記憶體數量,
  • CD/DVD燒錄器能控制系統其他部分使用的記憶體數量以確保燒錄不會因為缺少記憶體而失敗,
  • 還有幾個其他用例,查找或者使用控制器只是為了好玩(學習和hack進虛擬機),

當前狀態: linux-2.6.34-mmotm(development version of 2010/April),

功能特性:

  • 統計和限制匿名頁面、檔案快取、交換快取的用量,
  • 頁面能排他性地連接到per-memcg LRU,而不是全域的LRU,
  • 任意地統計和限制memory+swap的用量,
  • 層次結構化的統計,
  • 軟限制
  • moving (recharging) account at moving a task is selectable.
  • 用量閾值通知器,
  • 記憶體壓力通知器
  • oom-killer禁用開關和oom-notifier
  • 跟控制組無限控制,

內核記憶體支持是一個正在進行的作業,當前版本提供了基本功能(2.7節),

控制檔案概要

名稱 說明
tasks 系結任務(執行緒)并現實執行緒串列
cgroup.procs 顯示行程串列
cgroup.event_control event_fd()的介面, CONFIG_PREEMPT_RT系統不可用
memory.usage_in_bytes 當前記憶體用量
memory.memsw.usage_in_bytes 當前memory+Swap用量
memory.limit_in_bytes 設定/顯示記憶體用量限制
memory.memsw.limit_in_bytes 設定/顯示memory+Swap用量限制
memory.failcnt 顯示記憶體用量觸達閾值的次數
memory.memsw.failcnt 顯示memory+Swap用量觸達閾值的次數
memory.max_usage_in_bytes 顯示記錄的最大記憶體用量
memory.memsw.max_usage_in_bytes 顯示記錄的最大memory+Swap用量
memory.soft_limit_in_bytes 設定/顯示記憶體用量軟限制, CONFIG_PREEMPT_RT系統不可用
memory.stat 顯示狀態統計
memory.use_hierarchy 設定/顯示分層數量,已過時不要使用
memory.force_empty 觸發強制頁面回收
memory.pressure_level 設定記憶體壓力通知
memory.swappiness 設定/顯示vmscan的swappiness引數
memory.move_charge_at_immigrate 設定/顯示moving charges控制
memory.oom_control 設定/顯示oom控制
memory.numa_stat 顯示每個numa節點的記憶體使用數量
memory.kmem.limit_in_bytes 已過時
memory.kmem.usage_in_bytes 顯示內核記憶體分配用量
memory.kmem.failcnt 顯示內核記憶體用量觸達限制的次數
memory.kmem.max_usage_in_bytes 顯示記錄的最大內核記憶體用量
memory.kmem.tcp.limit_in_bytes 設定/顯示TCP緩沖記憶體的硬限制
memory.kmem.tcp.usage_in_bytes 顯示TCP緩沖記憶體分配用量
memory.kmem.tcp.failcnt 顯示TCP緩沖記憶體用量觸達限制的次數
memory.kmem.tcp.max_usage_in_bytes 顯示記錄的最大TCP緩沖記憶體用量

1. 歷史

記憶體控制器有一段很長的歷史,記憶體控制器的需求描述是Balbir Singh [1]發表的,同時RFC發布了記憶體控制的幾個實作方式,RFC的目標是為記憶體控制的最小化需求特性構建共識和認可,西一個RSS控制器被Balbir Singh[2]在2007年2月發表,Pavel Emelianov [3][4][5]又發表了3個版本的RSS控制器,在OLS,在資源管理BoF,每個人都建議我們頁面快取和RSS都一起處理,另一個需求被提出來允許用戶空間處理OOM,現在的記憶體控制器是版本6,它結合了RSS和頁面快取控制[11],

2. 記憶體控制

記憶體是一種數量有限的獨特資源,如果任務請求需求CPU來處理,任務能通過小時/天/月或者年的周期來擴展它的處理能力,但是記憶體只能被復用來完成任務,
記憶體控制器的實作已經被劃分成多個階段,他們是:

  1. Memory controller
  2. mlock(2) controller
  3. Kernel user memory accounting and slab control
  4. user mappings length controller

記憶體控制器是第一個已經被開發出來的控制器,

2.1. 設計

設計的核心是一個名叫page_counter的計數器,page_counter跟蹤控制器相關的行程組的當前記憶體用量和限制,每個控制組有記憶體控制器相關的資料結構(mem_cgroup),

2.2. 統計

     +--------------------+
     |  mem_cgroup        |
     |  (page_counter)    |
     +--------------------+
      /            ^      \
     /             |       \
+---------------+  |        +---------------+
| mm_struct     |  |....    | mm_struct     |
|               |  |        |               |
+---------------+  |        +---------------+
                   |
                   + --------------+
                                   |
+---------------+           +------+--------+
| page          +---------->  page_cgroup|
|               |           |               |
+---------------+           +---------------+
(Figure 1: Hierarchy of Accounting)

圖1顯示了控制器的幾個重要方面:

  1. 以控制組(per cgroup)為單位進行統計
  2. 每個mm_struct知道它屬于哪個cgroup
  3. 每個頁面有一個指標指向page_cgroup,它知道cgroup屬于哪個控制組,

統計按照如下方式完成:mem_cgroup_charge_common() 被呼叫來構建必須的資料結構,檢查正在記賬的控制組是否超過限制,如果超過,那么在控制組內回收就會被呼叫,更多回收詳情參看本檔案的回收章節,如果一切正常,page_cgroup就會更新,page_cgroup在控制組內有他自己的LRU,page_cgroup結構在啟動或者記憶體熱插拔時被分配,

2.2.1 統計詳情

所有映射的anon頁面 (RSS) 和快取頁面 (Page Cache) 都會被統計, 永遠不可回收的和不會用在LRU上的那些頁面不會被統計,我們只統計通用VM管理下的頁面,

RSS頁面統計在page_fault上,除非他們之前已經統計過,檔案頁面插入到inode(radix-tree)時作為Page Cache統計,當它被映射到行程頁表中時,要避免重復地統計,

完全未映射的RSS頁面是沒有統計的,從radix-tree中移除的PageCache頁面也沒有統計,甚至如果RSS頁面完全沒有被kswapd映射,他們可以作為SwapCache存在以直到被釋放,這些SwapCaches也會被統計,swapped-in頁面在添加到swapcache之后會被統計,

注意: 內核會一次性swapin-readahead和讀取多個swap,從頁面的memcg記錄到swap開始而不管memsw是否被使能,頁面在swapin之后都會被統計,

頁面遷移時,統計資訊會被保留,

注意:我們統計pages-on-LRU是因為我們的目的是控制已用頁面的數量,not-on-LRU頁面從VM視角來看是超出控制的,

2.3 共享頁面統計

共享頁面在“第一次觸達頁面方法”(first touch approach)的基礎上統計,第一次觸達頁面的控制組被統計為頁面(?)這種方法背后的原理是使用共享頁面的控制組最后會因此而被記賬,(一旦它未被從控制組中記賬,它將會發生記憶體壓力),

但是看一下8.2小節:當移動任務到另一個控制組,如果move_charge_at_immigrate被選擇,它的頁面就可以被重新記賬到新的控制組,

2.4 交換記憶體擴展(Swap Extension)

交換記憶體使用總是被記錄,交換記憶體擴展允許讀取和限制它,

當CONFIG_SWAP使能,下列檔案就會被增加:

  • memory.memsw.usage_in_bytes
  • memory.memsw.limit_in_bytes

memsw表示memory+swap,memory+swap的用量是由memsw.limit_in_bytes限制的,

例如:假設系統有4G交換記憶體,不小心在2G記憶體限制下分配了6G記憶體,任務將會使用掉所有的交換記憶體,在這種情況下,設定memsw.limit_in_bytes=3G可以防止交換記憶體更壞的使用情況,通過使用memsw限制,你可以避免因為交換記憶體的缺乏而引起的系統OOM,

為什么是memory+swap而不是swap?
全域LRU(kswapd)能換出任何頁面,換出意味著移動統計從記憶體切到了交換記憶體,而使用memory+swap則不會有任何改變,換句話說,當我們想要限制交換記憶體的用量而不影響全域LRU,從OS視角的觀點來看,memory+swap的限制方式比僅僅限制交換記憶體要更好,

控制組觸達memory.memsw.limit_in_bytes時會發生什么?
當控制組觸達memory.memsw.limit_in_bytes,在該控制組內做swap-out是沒有用的,swap-out也不可以由控制組程式和已摘除的檔案快取來進行,但是如上所述,為了系統記憶體管理狀態的正常,全域LRU能從控制組換出記憶體,控制組不能阻止它,

2.5 回收Reclaim

每個控制組維護著每個控制組的跟全域VM結構相同的LRU,當控制組超過它的限制,我們首先試著從控制組內回收記憶體以便預留新的空閑頁面,如果回收不成功,OOM程式被呼叫來殺死控制組內最龐重的任務,(參看第10小節OOM控制)

回收演算法沒有為控制組做修改,被選做回收的頁面來自每個控制組的LRU串列,

注意:
回收不會對根控制組生效,因為我們不能在根控制組上設定任何限制,

注意2:
當panic_on_oom設定為2,整個系統就會panic,
當OOM時間通知器已經注冊,時間就會被發出,(參看oom_control小節)

2.6 鎖Locking

鎖順序如下:

Page lock (PG_locked bit of page->flags)  
  mm->page_table_lock or split pte_lock  
    lock_page_memcg (memcg->move_lock)  
      mapping->i_pages lock  
        lruvec->lru_lock  

Per-node-per-memcgroup LRU (控制組私有LRU) 由lruvec->lru_lock來守護; 從lruvec->lru_lock分離出頁面之前,PG_lru bit of page->flags會被清除,

2.7 內核記憶體擴展(CONFIG_MEMCG_KMEM)

記憶體控制器能用內核記憶體擴展來限制系統使用的內核記憶體數量,內核記憶體完全不同于用于記憶體,因為它不能被交換出去,這使得它有可能通過消耗太多的這種昂貴資源來Dos系統,

內核記憶體統計對所有記憶體控制組默認為使能的,但是它能在啟動時傳遞cgroup.memory=nokmem選項給內核來禁用,這種情況下內核記憶體根本就不會被統計,

內核記憶體限制對根控制組沒有影響,根控制組的用量可以統計,也可以不用統計,已用的記憶體會被累加到memory.kmem.usage_in_bytes中或者獨立的計數器中,

主kmem計數被傳遞給主計數器,因此kmem統計也可以從用戶計數器里看到,

當前沒有為內核記憶體實作軟限制,當這些限制作業完成之后未來的作業就是出發slab回收,

2.7.1 當前統計的內核記憶體資源

stack pages:
每個行程消耗一些堆疊頁面,通過記賬到內核記憶體,我們可以防止新行程創建太高的內核記憶體,

slab pages:
SLAB或者SLUB分配器分配的頁面都會被跟蹤,每當第一次從memcg內創建快取時,每個kmem_cache的副本就會創建出來,創建是lazily的,因為當正在創建快取時有些物件仍然能被跳過,slab頁面內的所有物件應該屬于同一個memcg,當任務在頁面分配期間被移動到不同的memcg時就會失敗,

sockets memory pressure:
有些套接字協議有記憶體壓力閾值,記憶體控制器允許他們分別由每個控制組分別地而不是全域地被控制

tcp memory pressure:
TCP協議的套接字記憶體壓力

2.7.2 常用用例

因為"kmem"計數被傳遞給主用戶計數器,內核記憶體限制絕對不會跟用戶記憶體完全無關,"U"是用戶限制,"K"是內核限制,有三種方式能設定限制:
U != 0, K = unlimited:
這是標準memcg限制機制,內核記憶體完全被忽略,

U != 0, K < U:
內核記憶體是用戶記憶體的子集,在每個控制組記憶體數量被超量分配時這種方式是有用的,超量的內核記憶體限制肯定不推薦,因為box仍然能在不可回收的記憶體之外運行,這種情況下,管理員能設定"K"以便所有控制組總數絕不會超過總的記憶體,隨意地在QOS成本范圍上設定"U",

警告:
在當前的實作中,記憶體回收不會在觸達K而小于U時被控制組觸發,

U != 0, K >= U:
因為kmem統計被傳遞給用戶計數器,控制組將會觸發兩種記憶體的回收,這種設定給管理員一個統一的記憶體視角,

3. 用戶介面

配置:

  • 使能CONFIG_CGROUPS
  • 使能CONFIG_MEMCG
  • 使能CONFIG_MEMCG_SWAP(來使用swap記憶體擴展)
  • 使能CONFIG_MEMCG_KMEM (來使用kmem記憶體擴展)

準備控制組:

# mount -t tmpfs none /sys/fs/cgroup
# mkdir /sys/fs/cgroup/memory
# mount -t cgroup none /sys/fs/cgroup/memory -o memory

創建新控制組,移入當前bash:

# mkdir /sys/fs/cgroup/memory/0
# echo $$ > /sys/fs/cgroup/memory/0/tasks

此刻開始我們就在0控制組內,更改記憶體限制:

# echo 4M > /sys/fs/cgroup/memory/0/memory.limit_in_bytes

注意:
我們可以使用后綴(k, K, m, M, g or G)來表示位元組單位值,

注意:
我們能寫"-1"來重置*.limit_in_bytes為無限制,

注意:
我們不能在根控制組下設定任何限制,

# cat /sys/fs/cgroup/memory/0/memory.limit_in_bytes
4194304

我們能檢查用量:

# cat /sys/fs/cgroup/memory/0/memory.usage_in_bytes
1216512

對這個檔案的寫成功并不保證寫入檔案的值被變成了設限的設定,這可能因為很多原因,例如湊整到了頁面邊界或者系統記憶體的總量,在寫入之后,要求用戶重讀取這個檔案來保證值已經被內核提交:

# echo 1 > memory.limit_in_bytes
# cat memory.limit_in_bytes
4096

memory.failcnt域給出了控制組限制超過的次數,
memory.stat檔案給出了統計資訊,現在快取、RSS和激活/不激活頁面數量都能被顯示了,

4. 測驗

為了測驗功能和實作,可以參看Memcg實作demo,

性能測驗也很重要,要查看純記憶體控制器的開銷,tmpfs上的測驗將會給你很好看的少量開銷數字,

缺頁(Page-fault)的可測量性也很重要,在平行缺頁測驗中,多行程測驗比單行程測驗要好是因為有共享物件/狀態的噪音,

但是上述兩種是極限測驗條件,試著做記憶體控制器下的正常測驗總是有好幫助的,

4.1 疑難解答

有時用戶可能發現控制組下的應用程式被OOM killer殺死了,它有幾種原因:

  1. 控制組限制太高,
  2. 用戶正在使用匿名記憶體,而交換記憶體被關倍訓者太低了,

通過同步echo 1 > /proc/sys/vm/drop_caches將會幫助除去控制組中的快取的一些頁面(page cache pages),

要想知道發生了什么,禁用OOM_Kill為“10. OOM Control”,再來看看發生的情況,

4.2 任務遷移

當任務從一個控制組遷移到另一個控制組,它的統計默認是不會攜帶走的,從源控制組分配的頁面仍然會保持記賬,當頁面被釋放或者回收后記賬才會摘除,

你可以隨著任務遷移移動記賬,參看第8章“任務遷移時移動記賬”

4.3 移除控制組

控制組可以通過rmdir來移除,但是根據4.1和4.2小節的討論,即使所有任務已經遷移出去了控制組可能仍有一些統計記賬,(因為我們的記賬是針對頁面而不是針對任務)

我們移動統計到父層就不會有記賬變化,

在交換記憶體中的記賬資訊在移除控制組時不會被更新,記錄的資訊會被丟棄,使用交換記憶體的控制組會作為新的屬主來記賬,

5. 其他介面

5.1 force_empty

memory.force_empty介面可以使控制組的記憶體用量為空:

# echo 0 > memory.force_empty

控制組將被回收,頁面也會被盡可能地回收,

這個介面的典型用例就是在呼叫rmdie()前,通過rmdir()來使得memcg離線,但是由于檔案快取已經被記賬,memcg仍然可能呆在原地不動,一些超出使用的頁面快取可能會保持記賬一直到記憶體壓力發生,如果你想要避免這些,force_empty就很有用,

5.2 stat檔案

memory.stat檔案包含下列統計資訊:

記憶體控制組本地狀態

名稱 說明
cache # of bytes of page cache memory.
rss # of bytes of anonymous and swap cache memory (includes transparent hugepages).
rss_huge # of bytes of anonymous transparent hugepages.
mapped_file # of bytes of mapped file (includes tmpfs/shmem)
pgpgin # of charging events to the memory cgroup. The charging event happens each time a page is accounted as either mapped anon page(RSS) or cache page(Page Cache) to the cgroup.
pgpgout # of uncharging events to the memory cgroup. The uncharging event happens each time a page is unaccounted from the cgroup.
swap # of bytes of swap usage
dirty # of bytes that are waiting to get written back to the disk.
writeback # of bytes of file/anon cache that are queued for syncing to disk.
inactive_anon # of bytes of anonymous and swap cache memory on inactive LRU list.
active_anon # of bytes of anonymous and swap cache memory on active LRU list.
inactive_file # of bytes of file-backed memory on inactive LRU list.
active_file # of bytes of file-backed memory on active LRU list.
unevictable # of bytes of memory that cannot be reclaimed (mlocked etc).

分層架構相關的狀態 (memory.use_hierarchy)

hierarchical_memory_limit # of bytes of memory limit with regard to hierarchy under which the memory cgroup is
hierarchical_memsw_limit # of bytes of memory+swap limit with regard to hierarchy under which memory cgroup is.
total_ # hierarchical version of , which in addition to the cgroup’s own value includes the sum of all hierarchical children’s values of , i.e. total_cache

下面這些額外的統計資訊跟CONFIG_DEBUG_VM相關:

recent_rotated_anon VM internal parameter. (see mm/vmscan.c)
recent_rotated_file VM internal parameter. (see mm/vmscan.c)
recent_scanned_anon VM internal parameter. (see mm/vmscan.c)
recent_scanned_file VM internal parameter. (see mm/vmscan.c)

備忘錄:
recent_rotated表示最近的LRU翻轉頻率,recent_scanned表示最近的LRU掃描,顯示出來是為了好除錯,

注意:
僅僅匿名和swap快取記憶體被作為rss統計的一部分被列舉,這個不應該跟resident set size或者控制組使用的物理記憶體弄混淆,
'rss + mapped_file'給出來的才是控制組的resident set size,

注意:
檔案和shmem可以跟其它控制組共享,在此情況下,只有當記憶體控制組是頁面快取的屬主時mapped_file才會被統計,

5.3 swappiness

特定的組可以覆寫 /proc/sys/vm/swappiness,在根控制組下可調整全域相關的swappiness設定

注意:
不同于全域回收,有限回收強制swappiness為0來防止任何交換,即使有交換記憶體可用也不行,在沒有檔案頁面可回收的情況下這可能會導致memcg的OOM-killer,

5.4 failcnt

記憶體控制組提供了memory.failcnt和memory.memsw.failcnt檔案,這個failcnt失敗次數顯示了用量計數器觸達限制的次數,當記憶體控制組觸及限制failcnt就會增加,控制組內的記憶體將會被回收,

你可以重置failcnt為0:

# echo 0 > .../memory.failcnt

5.5 usage_in_bytes

記憶體控制組使用一些優化措施來避免不必要的cacheline失敗共享,usage_in_bytes不會顯示記憶體(和交換記憶體)用量的精確值,它是一個模糊值,如果你想要知道更精確的記憶體用量,你應該使用memory.stat中的RSS+CACHE(+SWAP)值,

5.6 numa_stat

它跟numa_maps相似但是基于per-memcg操作,......

每個memcg的numa_stat檔案包含“total”,“file”,“anon”和“unevictable”,......

memory.numa_stat的輸出格式:

total=<total pages> N0=<node 0 pages> N1=<node 1 pages> ...
file=<total file pages> N0=<node 0 pages> N1=<node 1 pages> ...
anon=<total anon pages> N0=<node 0 pages> N1=<node 1 pages> ...
unevictable=<total anon pages> N0=<node 0 pages> N1=<node 1 pages> ...
hierarchical_<counter>=<counter pages> N0=<node 0 pages> N1=<node 1 pages> ...

“total”數量是file+anon+unevictable的總和,

6. 分層支持

記憶體控制器支持深度分層和分層級統計,分層是通過在控制組檔案系統下創建控制組來生成的,例如有如下一個控制組分層:

    root
  /  |   \
 /   |    \
a    b     c
           | \
           |  \
           d   e

上圖中分層統計也會被使能,所有e的記憶體用量被統計上溯到它的祖宗c和root上,如果有一個父系過量了,回收演算法就會從祖宗和其后代的任務中回收,

6.1 分層統計和回收

分層統計默認是使能的,禁用分層統計已經過時了,試圖這么做會導致失敗并列印警告到dmesg中,

為了兼容,memory.use_hierarchy總是要寫入1:

# echo 1 > memory.use_hierarchy

7. 軟限制Soft limits

軟限制允許更多個記憶體共享,軟限制背后的思想是允許控制組按需使用記憶體,提供如下機制:

  1. 沒有記憶體爭奪,
  2. 不會超過硬限制,

當系統探測到記憶體爭奪或者低記憶體時,控制組就會后推他們的軟限制,如果軟限制非常高,他們就會被盡可能后推來確保控制組不會產生記憶體饑餓,
...

7.1 介面

使用下面命令來設定軟限制:

# echo 256M > memory.soft_limit_in_bytes

如果想要改為1G:

# echo 1G > memory.soft_limit_in_bytes

注意:
從記憶體控制組內記憶體回收呼叫開始,軟限制會影響一段很長期的時間,

注意:
建議軟限制總是設定在在硬限制之下,否則硬限制就會獲得優先,

8. 任務遷移時的移動記賬

用戶能隨著任務的遷移對任務進行移動記賬,也就是說,舊控制組內未記賬的任務頁面將會在新控制組內記賬,這個特性在非CONFIG_MMU環境內因為缺乏頁表而不被支持,

8.1 介面

這個特性默認是禁用的,可以寫入到目的控制組memory.move_charge_at_immigrate檔案來使能:

# echo (some positive value) > memory.move_charge_at_immigrate

注意:
每個位元位各有意義,應當移動哪種記賬型別,

注意:
只在你移動mm->owner時記賬才會移動,換句話說,就是執行緒組的領導(原文:a leader of a thread group),

注意:
如果我們在目的控制組沒有找到足夠空間給任務,我們會試著通過回收記憶體來制造空間,如果不能制造足夠的空間,任務遷移會失敗,

注意:
移動記賬可能耗費幾秒時間,

再次禁用移動記賬:

# echo 0 > memory.move_charge_at_immigrate

8.2 可被移動的記賬型別

每個位元位各有意義,應當移動哪種記賬型別,但是在任何情況下,當記賬到任務當前的(或者舊的)記憶體控制組時,必須說明能被移動的頁面或者swap的數量,

bit 可被移動的記賬型別
0 目標任務用到的匿名頁(或者交換記憶體),必須使能Swap Extension(2.4小節)
1 目標任務映射的檔案頁(正常檔案、tmpfs檔案<ipc共享記憶體>和tmpfs交換記憶體),<省略幾句話>,必須使能Swap Extension(2.4小節)

8.3 TODO

所有的移動記賬操作在cgroup_mutex下進行,...

9. 記憶體閾值

記憶體控制組用控制組通知API實作記憶體閾值,允許注冊多個mem和memsw閾值來獲得通知,

要注冊閾值,應用程式必須:

  • 用eventfd(2)來創建eventfd;
  • 打開memory.usage_in_bytes或者memory.memsw.usage_in_bytes;
  • 寫入字串"<event_fd> "到cgroup.event_control

應用程式在記憶體用量的到達閾值時會被eventfd通知到,它對root和non-root控制組都是適用的,

10. OOM Control

memory.oom_control檔案用作OOM通知和其他控制,

記憶體控制組使用控制組通知API實作了OOM通知器,允許注冊多個OOM通知,

要注冊通知器,應用程式必須:

  1. 用eventfd(2)創建eventfd句柄,
  2. 打開memory.oom_control檔案,
  3. 寫入字串“<event_fd> ”到cgroup.event_control,
    當OOM發生時,應用程式將會通過eventfd被通知到,OOM通知對根控制組不生效,

你可以這樣來禁用OOM-killer:

#echo 1 > memory.oom_control

如果OOM-killer被禁用,當控制組下的任務請求可統計的記憶體時,他們將會在記憶體控制組的OOM-waitqueue佇列里掛起/睡眠,

為了運行它,你必須釋放記憶體控制組的OOM狀態,通過:

  • 擴大限制或者減少用量

為了減少用量:

  • 殺死一些任務,
  • 移動一些任務到其他控制組,攜帶著記賬遷移,
  • 移除一些檔案(在tmpfs內?)

然后停止的任務會重新作業了,

在讀取時,當前的OOM狀態被顯示:

  • oom_kill_disable:0或者1 (1表示oom-killer禁用)
  • under_oom:0或1 (1表示記憶體控制組在OOM下,任務可以被停止)
  • oom_kill:整數計數器,控制組內被OOM killer殺死的行程數量,

11. 記憶體壓力

壓力等級通知能被用來監測記憶體分配成本,基于壓力,應用程式能實作不同的記憶體資源管理策略,壓力等級定義如下:

  • “low”水平表示系統正在回收記憶體,監控回識訓動對于維護快取水平會有幫助的,在通知中,程式(一般是Activity Manager)可以分析vmstat然后提前采取行動(例如關閉不重要的服務),
  • “medium”水平表示系統正在經歷中等記憶體壓力,系統可能正在產生交換記憶體,分配檔案快取等等,在這個事件中,應用程式可以進一步分析vmstat/zoneinfo/memcg或者內部記憶體用量統計,釋放那些能很容易重建或者從磁盤中重新讀取的任何資源,
  • “critical”水平表示系統正在遭受沖擊,即將要觸發OOM,應用程式應該盡其所能幫助系統,此時來咨詢vmstat或者其他統計資料可能已經太晚了,建議立刻采取行動,

默認情況下,事件會被層層繁衍上報,直到被處理為止,就是說事件不會穿透,例如,你有三個控制組A->B->C,現在你在控制組A、B、C上都配置了事件監聽器,假設C控制組經受到了壓力,此時只有C會收到通知,而A和B不會收到,這么做避免了過度廣播訊息干擾系統,如果我們在低記憶體或者遭受連續沖擊的情況下會特別有壞處,如果C沒有事件監聽器,那么B將會收到通知,

有三種可選模式來定義不同的上報行為:

  • “default”: 默認行為,這種模式忽略可選模式引數,留作后向兼容,
  • “hierarchy”: 事件總是被上報到根,不管是否有事件監聽器,上述例子中,控制組A、B、C都會收到壓力等級的通知,
  • “local”: 事件被穿透,只有注冊了通知的memcg會收到通知,上述例子中,如果控制組C注冊了“local”通知,那么C將會收到通知,如果控制組B注冊了“local”通知,然而控制組B絕對不會收到通知,不管C是否注冊了事件監聽器,

壓力等級和事件通知模式是以逗號分隔符字串定義的,例如“low,hierarchy”定義了分層穿透通知到所有祖先memcg,通知默認是非穿透的,“medium,local”為中等水平定義了穿透通知,

memory.pressure_level檔案只是被用來配置eventfd句柄,要注冊同志,應用程式必須:

  1. 用eventfd(2)創建eventfd句柄,
  2. 打開memory.pressure_level,
  3. 寫入字串“<event_fd> <level[,mode]>”到cgroup.event_control,
    應用程式在記憶體壓力達到或超過指定的等級水平時將會通過eventfd被通知到,對memory.pressure_level的讀寫操作沒有被實作,

測驗:
這里有個小腳本,創建新控制組,配置記憶體限制,配置通知然后在子控制組中經受critical壓力:

# cd /sys/fs/cgroup/memory/
# mkdir foo
# cd foo
# cgroup_event_listener memory.pressure_level low,hierarchy &
# echo 8000000 > memory.limit_in_bytes
# echo 8000000 > memory.memsw.limit_in_bytes
# echo $$ > tasks
# dd if=/dev/zero | read x
(Expect a bunch of notifications, and eventually, the oom-killer will trigger.)

12. TODO

  1. Make per-cgroup scanner reclaim not-shared pages first
  2. 教會控制器來對共享頁面做統計,
  3. 當限制仍舊沒有觸達而用量正在接近時在后臺啟動回收,

總結

總而言之,記憶體控制器是穩定的控制器,已經被提交了,在社區里也得到非常廣泛地討論,

References

  1. Singh, Balbir. RFC: Memory Controller, http://lwn.net/Articles/206697/
  2. Singh, Balbir. Memory Controller (RSS Control), http://lwn.net/Articles/222762/
  3. Emelianov, Pavel. Resource controllers based on process cgroups https://lore.kernel.org/r/[email protected]
  4. Emelianov, Pavel. RSS controller based on process cgroups (v2) https://lore.kernel.org/r/[email protected]
  5. Emelianov, Pavel. RSS controller based on process cgroups (v3) https://lore.kernel.org/r/[email protected]
  6. Menage, Paul. Control Groups v10, http://lwn.net/Articles/236032/
  7. Vaidyanathan, Srinivasan, Control Groups: Pagecache accounting and control subsystem (v3), http://lwn.net/Articles/235534/
  8. Singh, Balbir. RSS controller v2 test results (lmbench), https://lore.kernel.org/r/[email protected]
  9. Singh, Balbir. RSS controller v2 AIM9 results https://lore.kernel.org/r/[email protected]
  10. Singh, Balbir. Memory controller v6 test results, https://lore.kernel.org/r/20070819094658.654.84837.sendpatchset@balbir-laptop
  11. Singh, Balbir. Memory controller introduction (v6), https://lore.kernel.org/r/20070817084228.26003.12568.sendpatchset@balbir-laptop
  12. Corbet, Jonathan, Controlling memory use in cgroups, http://lwn.net/Articles/243795/

.


英文原文:
https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html
https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memcg_test.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/491743.html

標籤:其他

上一篇:每次開機docker-desktop都啟動失敗了

下一篇:加入資料框并合并/替換列值

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more