測試環境centos7 ,內核版本4.20html
內核使用cgroup對進程進行分組,並限制進程資源和對進程進行跟蹤。內核經過名爲cgroupfs類型的虛擬文件系統來提供cgroup功能接口。cgroup有以下2個概念:node
# cat /proc/cgroups #subsys_name hierarchy num_cgroups enabled cpuset 8 6 1 cpu 7 105 1 cpuacct 7 105 1 blkio 5 105 1 memory 3 327 1 devices 6 106 1 freezer 4 6 1 net_cls 2 6 1 perf_event 11 6 1 net_prio 2 6 1 hugetlb 9 6 1 pids 12 106 1 rdma 10 1 1
系統默認會掛載cgroup,路徑爲/sys/fs/cgroup,查看當前系統掛載的cgroup,能夠看到在默認路徑下掛載了全部的子系統。後續能夠直接使用下述hierarchy做爲父hierarchy。進程的cgroup能夠在/proc/$pid/cgroup文件中查看。linux
# mount|grep cgroup tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,seclabel,mode=755) cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd) cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,perf_event) cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,hugetlb) cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,rdma) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpu,cpuacct) cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,net_cls,net_prio) cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuset) cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,blkio) cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,freezer) cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,memory) cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,pids) cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,devices)
cgroup有以下4個規則:git
[root@ memory]# echo $$ 9439 [root@ memory]# echo $$ > mem1/tasks [root@ memory]# cat mem1/tasks 9439 9680 [root@ memory]# echo $$ > mem2/tasks [root@ memory]# cat mem2/tasks 9439 9693 [root@ memory]# cat mem1/tasks [root@ memory]#
相同類型subsystem的hierarchy爲同一個hierarchy,以下例中建立一個包含memory subsystem的hierarchy,它與/sys/fs/cgroup下面的memory是一致的,在cgrp1中建立一個名爲mem1的cgroup。在/sys/fs/cgroup/memory下能夠看到新建立的mem1github
[root@ cgroup]# mount -t cgroup -o memory mem cgrp1/ [root@ cgroup]# cd cgrp1/ [root@ cgrp1]# mkdir mem1
[root@ mem1]# echo $$ 10928 [root@ mem1]# echo $$>tasks [root@ mem1]# cat /proc/10928/cgroup 11:devices:/user.slice 10:perf_event:/ 9:pids:/user.slice 8:freezer:/ 7:cpuacct,cpu:/ 6:hugetlb:/ 5:memory:/mem1 4:cpuset:/ 3:net_prio,net_cls:/ 2:blkio:/ 1:name=systemd:/user.slice/user-1000.slice/session-1.scope [root@ mem1]# bash #建立一個子進程 [root@ mem1]# echo $$ 11402 [root@ mem1]# cat /proc/11402/cgroup 11:devices:/user.slice 10:perf_event:/ 9:pids:/user.slice 8:freezer:/ 7:cpuacct,cpu:/ 6:hugetlb:/ 5:memory:/mem1 4:cpuset:/ 3:net_prio,net_cls:/ 2:blkio:/ 1:name=systemd:/user.slice/user-1000.slice/session-1.scope
從上面能夠看到,subsystem相同的hierarchy是被重複使用的;當建立一個新的hierarchy時,若是使用的subsystem被其餘hierarchy使用,則會返回EBUSY錯誤。如/sys/fs/cgroup中已經在cpuset和memory中單獨使用了名爲cpuset和memory的subsystem,則從新建立一個包含了它們的hierarchy會返回錯誤web
[root@ cgroup]# mount -t cgroup -o cpuset,memory mem1 cgrp1/ mount: mem1 is already mounted or /cgroup/cgrp1 busy
能夠建立沒有subsystem的hierarchy,默認包含以下文件:算法
[root@ cgroup]# mount -t cgroup -onone,name=cgrp1 mycgroup cgrp1/ [root@ cgroup]# cd cgrp1/ [root@ cgrp1]# ll total 0 -rw-r--r--. 1 root root 0 Jan 2 23:54 cgroup.clone_children --w--w--w-. 1 root root 0 Jan 2 23:54 cgroup.event_control -rw-r--r--. 1 root root 0 Jan 2 23:54 cgroup.procs -r--r--r--. 1 root root 0 Jan 2 23:54 cgroup.sane_behavior -rw-r--r--. 1 root root 0 Jan 2 23:54 notify_on_release -rw-r--r--. 1 root root 0 Jan 2 23:54 release_agent -rw-r--r--. 1 root root 0 Jan 2 23:54 tasks
上面爲cgroup使用的通常規則,下面講解memory cgroupshell
linux memory基礎知識segmentfault
以32位系統爲例講解下linux內存分佈。linux內存分爲用戶空間和內核空間,用戶空間佔用0~3G的內存,內核空間佔用3~4G的內存。從下圖中能夠看到用戶空間的進程地址均爲動態映射(即虛擬地址和物理地址的映射,如使用malloc申請到的內存爲虛擬內存,只有對該內存進行訪問時纔會進行虛擬內存到物理內存的映射查找),而內核空間主要分爲了2種內存區域,物理頁面映射區和內核地址空間,前者能夠直接訪問物理地址且不會觸發缺頁異常(物理頁面直接映射),然後者與用戶空間用法同樣,爲動態映射。centos
當用戶空間使用malloc等系統調用申請內存時,內核會檢查線性地址對應的物理地址,若是沒有找到會觸發一個缺頁異常,進而調用brk或do_map申請物理內存(brk申請的內存一般小於128k)。而對於內核空間來講,它有2種申請內存的方式,slab(也有slob和slub)和vmalloc:
用戶空間和內核空間申請內存的方式以下:
linux使用"夥伴關係"算法來管理空閒的內存資源,能夠在/proc/buddyinfo中查看當前空閒的內存分佈狀況,注意到slab申請物理內存時並無缺頁異常。(Linux使用分頁機制管理物理內存,將物理內存劃分爲4k大小的頁面(使用getconf PAGESIZE查看當前系統頁大小),當用戶使用malloc申請內存時能夠以kb爲單位指定內存大小,但內核在申請內存時是以頁爲單位申請實際的物理內存。linux系統的針對大內存分配經過「夥伴關係」算法進行維護,能夠在/proc/buddyinfo文件中查看當前空閒內存的劃分。buddyinfo使用list保存了連續的物理內存,申請內存時會遍歷該list,找到合適的內存並將其從該list上移除,將其註冊到內存的tables上。
linux 內存回收
linux使用LRU(least recently used)來回收內存頁面,LRU維護2個list,active和inactive,每一個list上維護了2種類型的內存映射:文件映射(file)和匿名映射(anon),因此LRU上的內存也就分爲了Active(anon)、Inactive(anon)、Active(file)和Inactive(file)4種類型,對應memory.stat中的inactive_anon,active_anon,inactive_file,active_file。匿名映射包含使用malloc或mmap(MAP_ANONYMOUS方式)申請的內存以及swap cache和shmem(見下),其內存不對應具體的文件,故稱爲匿名映射;文件映射對應的內存又稱爲file-backed pages,包含進程的代碼、映射的文件,在運行一個新的程序時該內存會增長。
當系統出現內存不足時,首先會想到使用free命令查看當前系統的內存狀況,以下例中,系統free內存爲65M,available爲85M,多出的20M爲buff/cache中能夠釋放的部分。swap用於在內存不足時將數據從內存swap到硬盤上。
# free -m total used free shared buff/cache available Mem: 972 660 65 28 246 85 Swap: 2047 51 1996
使用free命令能夠看到內存的大體狀況,若是須要更詳細的信息,就須要結合/proc/meminfo文件。/proc/meminfo文件中通常只要關注與LRU相關的內存便可,即Active(anon)、Inactive(anon)、Active(file)和Inactive(file)。須要注意的是,內核在統計內存時,只統計產生了缺頁異常的內存(即實際的物理內存),若是隻是申請了內存,而沒有對內存進行訪問,則不會加入統計。
其中Active(file)+Inactive(file)+Shmem=Cached+Buffers(若是內存沒有指定mlock),Buffers主要用於塊設備的存儲緩存,該值一般比較小,因此Active(file)+Inactive(file)+Shmem一般也能夠認爲是Cached,Cached表示了當前的文件緩存。Shmem表示share memory和tmpfs+devtmpfs佔用內存空間的總和(因爲share memory就是tmpfs實現的,實際上shemem就是各類tmpfs實現的內存的總和。可使用ipcs查看共享內存大小,使用df -k查看掛載的tmpfs文件系統),該值與free命令的shared相同。全部tmpfs類型的文件系統佔用的空間都計入共享內存。注:ipc中共享內存,消息隊列和信號量的底層實現就是基於tmpfs的。
下面建立一個200M的tmpfs的文件系統,能夠看到在建立先後內存並無變化,緣由是此時並無訪問內存,/tmp/tmpfs的空間利用率爲0%
# mkdir /tmp/tmpfs # free -m total used free shared buff/cache available Mem: 972 673 63 29 235 70 Swap: 2047 58 1989 # mount -t tmpfs -o size=200M none /tmp/tmpfs/ # free -m total used free shared buff/cache available Mem: 972 674 62 29 235 70 Swap: 2047 58 1989 # df -k Filesystem 1K-blocks Used Available Use% Mounted on ... none 204800 0 204800 0% /tmp/tmpfs
在上述文件系統下建立一個100M的文件,再次查看內存,能夠看到shared增長了100M。查看/proc/meminfo,能夠看到Shmem和Cached都增長了100M
# echo 3 > /proc/sys/vm/drop_caches # free -m total used free shared buff/cache available Mem: 972 574 253 28 144 212 Swap: 2047 157 1890 [root@ tmpfs]# dd if=/dev/zero of=/tmp/tmpfs/testfile bs=100M count=1 [root@ tmpfs]# free -m total used free shared buff/cache available Mem: 972 568 162 128 241 119 Swap: 2047 162 1885
在/proc/meminfo中還有一個Mapped值,用於統計映射的文件的大小。下面使用mmap映射上面生成的100M大小的testfile,注意mmap的選項爲MAP_ANONYMOUS|MAP_SHARED,它會建立一個匿名映射,實際上也是tmpfs的實現。下面須要有一個memset操做,不然這塊內存不會被統計進去
#include <stdlib.h> #include <stdio.h> #include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> int main() { void *ptr; int fd; fd = open("testfile", O_RDWR); if (fd < 0) { perror("open()"); exit(1); } ptr = mmap(NULL, 1024*1024*100, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, fd, 0); if (fd < 0) { perror("open()"); exit(1); } memset(ptr,0,1024*1024*100); getchar(); return 0; }
執行前查看當前的內存
# free -m total used free shared buff/cache available Mem: 972 538 174 128 260 140 Swap: 2047 192 1855
# ./mmap
在另一個shell界面查看內存,能夠看到shared增長了100M,對比/proc/meminfo先後差距,能夠看到Mapped增長了100M,Shmem增長了100M,Inactive(anon)也增長了100M。結束進程後,申請的內存會被釋放。
# free -m total used free shared buff/cache available Mem: 972 536 65 228 370 37 Swap: 2047 194 1853
但Mapped並非Shmem的子集,上述代碼的mmap僅使用MAP_SHARED時不會增長Shmem大小,僅表示映射的文件大小。
AnonPages表示不包含Shmem的匿名映射,AnonPages=Active(anon)+Inactive(anon)-Shmem
「Mlocked」統計的是被mlock()系統調用鎖定的內存大小。被鎖定的內存由於不能pageout/swapout,會從Active/Inactive LRU list移到Unevictable LRU list上。也就是說,當」Mlocked」增時,」Unevictable」也同步增長,而」Active」或」Inactive」同時減少;當」Mlocked」減少的時候,」Unevictable」也同步減少,而」Active」或」Inactive」同時增長。因爲swap會影響進程處理內存的效率,對內存進行鎖定能夠避免這段進程被交換到硬盤,增長數據處理效率
linux進程內存空間
32位系統下,linux中全部進程使用的內存佈局以下:
使用pmap能夠查看進程內存段的簡要信息,藉此能夠初步斷定是否存在內存泄漏或內存佔用過大的地方。pmap命令主要從/proc/$pid/smaps中獲取數值。以下代碼建立並使用100M內存
#include<stdlib.h> #include<stdio.h> int main() { int i=0; char *p = malloc(1024*1024*100); memset(p,1,1024); getchar(); return 0; }
編譯並執行上述代碼,使用pmap查看該進程的內存分佈以下,能夠看到有一個100M(102404K)大小的匿名內存佔用,即malloc申請的內存,此外也能夠看到動態庫libc佔用的內存,以及該進程的棧大小(棧默認8M,可使用ulimit -a查看)。更多參見Linux進程內存佈局
# pmap -x 52218 52218: ./test Address Kbytes RSS Dirty Mode Mapping 0000000000400000 4 4 0 r-x-- test 0000000000600000 4 4 4 r---- test 0000000000601000 4 4 4 rw--- test 00007f4b47564000 102404 4 4 rw--- [ anon ] 00007f4b4d965000 1800 256 0 r-x-- libc-2.17.so 00007f4b4db27000 2048 0 0 ----- libc-2.17.so 00007f4b4dd27000 16 16 16 r---- libc-2.17.so 00007f4b4dd2b000 8 8 8 rw--- libc-2.17.so 00007f4b4dd2d000 20 12 12 rw--- [ anon ] 00007f4b4dd32000 136 112 0 r-x-- ld-2.17.so 00007f4b4df39000 12 12 12 rw--- [ anon ] 00007f4b4df51000 8 4 4 rw--- [ anon ] 00007f4b4df53000 4 4 4 r---- ld-2.17.so 00007f4b4df54000 4 4 4 rw--- ld-2.17.so 00007f4b4df55000 4 4 4 rw--- [ anon ] 00007ffc73bf9000 132 16 16 rw--- [ stack ] 00007ffc73cd5000 8 4 0 r-x-- [ anon ] ffffffffff600000 4 0 0 r-x-- [ anon ] ---------------- ------- ------- ------- total kB 106620 468 92
linux可使用以下3種方式回收LRU上的內存:
(8+1485+15402)*4=16895,基本等於67584
# cat min_free_kbytes 67584 # cat /proc/zoneinfo |grep -E "zone|min" Node 0, zone DMA min 8 Node 0, zone DMA32 min 1485 Node 0, zone Normal min 15402
linux 32位和64位定義的zone是不一樣的,能夠在/proc/zoneinfo中查看zone的具體信息;注:numa場景下每一個內存被劃分到不一樣的node,每一個node含獨立的zone,關係以下:
以下能夠查看Node0 包含的zone(本機器只有一個node)
# cat zoneinfo |grep Node Node 0, zone DMA Node 0, zone DMA32
用戶進程的內存頁分爲兩種:file-backed pages(與文件對應的內存頁),和anonymous pages(匿名頁),好比進程的代碼、映射的文件都是file-backed,而進程的堆、棧都是不與文件相對應的、就屬於匿名頁。file-backed pages在內存不足的時候能夠直接寫回對應的硬盤文件裏,稱爲page-out,不須要用到交換區(swap)。/proc/meminfo中有一個dirty字段(全部的drity=Dirty+NFS_Unstable+Writeback),爲了維護數據的一致性,內核在清空內存前會對內存中的數據進行寫回操做,此時內存中的數據也被稱爲髒數據,若是須要清空的內存比較大,可能會消耗大量系統io資源;而anonymous pages在內存不足時就只能寫到硬盤上的交換區(swap)裏,稱爲swap-out,匿名頁即將被swap-out時會先被放進swap cache,在數據寫入硬盤後,swap cache纔會被free。下面爲swap-out和swap-in的流程.。注:tmpfs也能夠被swap-out;cached不包含swap cache。swap 和file-backed能夠參見該文檔
[swap-out] Make a page as swapcache → unmap → write out → free [swap-in] Alloc page → make it as swapcache → read from disk → map it.
更多linux內存的信息能夠參見這裏
memory cgroup 對內存的限制
內核擴展
cgroup內存的回收與上述linux系統的回收機制相似,每一個cgroup都有對應的LRU,當內存cgroup的內存達到限定值時會觸發LRU上的內存回收。須要注意的是cgroup沒法控制全局LRU的內存回收,所以在系統內存匱乏的時候,會觸發全局LRU上內存的swap操做,此時cgroup沒法限制這種行爲(如cgroup限制了swap的大小爲1G,但此時可能會超過1G)。下圖能夠看出cgoup的LRU控制的內存也在全局LRU所控制的範圍內。
memory cgroup的主要做用以下:
memory cgroup中以 memory.kmem.開頭的文件用於設置cgroup的內核參數,這些功能被稱爲內核內存擴展(CONFIG_MEMCG_KMEM),用於限制cgroup中進程佔用的內核內存資源,通常用的比較少。內核內存不會使用swap。系統默認會開啓這些功能,可使用以下命令查看是否打開:
# cat /boot/config-`uname -r`|grep CONFIG_MEMCG CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MEMCG_KMEM=y
cgroup中內核內存和用戶內存有以下限制關係(U表示用戶內存,K表示內核內存):
cgroup設置用戶內存
cgoup對用戶內存的限制主要是memory.limit_in_bytes和memory.memsw.limit_in_bytes。後者用於限制swap+memory的大小,前者則不限制swap。後者的值要不小於前者,所以在設置的時候優先設置memory.limit_in_bytes的值,當memory.limit_in_bytes==memory.memsw.limit_in_bytes時表示cgroup不使用swap
當新建立一個cgroup的時候,memory.limit_in_bytes和memory.memsw.limit_in_bytes默認不會對內存進行限制,使用全部的系統內存。
# echo 50M > memory.limit_in_bytes # cat memory.limit_in_bytes 52428800 # echo 50M > memory.memsw.limit_in_bytes # cat memory.memsw.limit_in_bytes 52428800
# echo $$ > tasks # dd if=/dev/zero of=/home/testfile bs=100M count=1 Killed
# echo 9223372036854771712 > memory.memsw.limit_in_bytes # dd if=/dev/zero of=/home/testfile bs=100M count=1 1+0 records in 1+0 records out 104857600 bytes (105 MB) copied, 0.740223 s, 142 MB/s # cat memory.max_usage_in_bytes 52428800 # cat memory.memsw.max_usage_in_bytes 113299456
memory.force_empty主要用於在執行rmdir刪除cgroup時儘可能清空cgroup佔用的內存。相似echo 3 > /proc/sys/vm/drop_caches
# cat memory.usage_in_bytes 86016 # echo 1 > memory.force_empty # cat memory.usage_in_bytes 0
memory.stat中的字段解析以下:
# per-memory cgroup local status cache - # of bytes of page cache memory. rss - # of bytes of anonymous and swap cache memory (includes transparent hugepages). #非正真的進程rss 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). # status considering hierarchy (see memory.use_hierarchy settings) 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.
memory.swappiness用於設置發生swap時內存的比例,設置值爲[0,100],100表示積極使用swap,0表示優先使用內存。cgroup中的swappiness做用與全局swappiness大致相似,用於限制本group中的swap使用。但cgroup中的swappiness在設置爲0時徹底禁止swap,而全局在內存不足時依然會使用swap,所以當cgroup中swappiness設置爲0時更容易發生OOM-kill。root cgroup中的swappiness設置對應全局swappiness。注:swappiness用於設置發生swap的內存比例,如設置爲60,表示內存在%(100-60)時開始發生swap。swappiness的設置建議以下
vm.swappiness = 0 :僅在內存不足的狀況下--當剩餘空閒內存低於vm.min_free_kbytes limit時,使用交換空間。 vm.swappiness = 1 :進行最少許的交換,而不由用交換。 vm.swappiness = 10:當系統存在足夠內存時,推薦設置爲該值以提升性能。 vm.swappiness = 60:系統默認值。這樣回收內存時,對file-backed的文件cache內存的清空比例會更大,內核將會更傾向於進行緩存清空而不是交換 vm.swappiness = 100:內核將積極的使用交換空間。
memory.failcnt 和memory.memsw.failcnt用於內存達到上限的次數,分別對應memory.limit_in_bytes和memory.memsw.limit_in_bytes。可使用echo 0>memory.failcnt重置。
memory.use_hierarchy用於設置cgroup內存的繼承管理,以下圖在設置了memory.use_hierarchy=1後,e group的內存會累計到它的祖先c和root。若是某個祖先的內存使用達到上限,則會在該祖先和它的子group中發生內存回收
root / | \ / | \ a b c| \ d e
以下圖在root cgroup下面建立一個子cgroup test1,在test1下面建立test2 和test3
root | | test1 / \ / \ test2 test3
在test1中設置不適用swap,且內存上限爲100M,查看當前內存使用爲0
# echo 100M > memory.limit_in_bytes # echo 100M > memory.memsw.limit_in_bytes # cat memory.usage_in_bytes 0
使用以下命令建立一個可執行文件,用於申請30M的內存,執行該程序,並將進程添加到test2 cgroup(注:進程只有在添加到cgroup以後的內存申請才受croup的限制,所以在t2進程添加到test 2 cgroup以後,回到t2進程執行界面,執行回車以執行malloc操做),能夠看到test2 cgroup的內存使用爲30M
#include<stdlib.h> #include<stdio.h> int main(int argc,char **argv) { getchar(); void *mem=malloc(30*1024*1024); memset(mem,0,30*1024*1024); getchar(); return 0; }
# echo 15570 > tasks # cat tasks 15570 # cat memory.usage_in_bytes 31588352
在test1 cgroup中查看內存使用,約30M
# cat memory.usage_in_bytes 31465472
建立t3進程,用於申請50M內存,操做同t2進程,在test1 cgroup下查看內存消耗,約80M
# cat memory.usage_in_bytes 83902464
修改t3進程申請內存的大小=100M,此時test1 cgroup的子cgrou總內存消耗超過了它的上限100M,在t3加入到test3的cgroup以後,在申請內存時會被oom-kill掉
# ./t3
Killed
memory.use_hierarchy能夠限制一個cgroup的總內存大小。當有子cgroup或父cgroup的use_hierarchy enabled時,沒法修改該值
memory.soft_limit_in_bytes用於調節內存的使用,該值不能大於memory.limit_in_bytes。當系統發現內存不足時,系統會儘可能將cgroup中的內存回退到memory.soft_limit_in_bytes設定的內存值如下。
memory.move_charge_at_immigrate用於控制線程在不一樣cgroup間移動時對內存charge的動做。當設置爲1時,當線程移動到另外一個cgroup時,其申請的內存頁也會移動到另外一個cgroup。默認不會。須要注意的是,轉移的線程必須是該線程組的主線程,且目標內存充足時才能遷移成功,不然會失敗,同時須要在目的cgroup中設置memory.move_charge_at_immigrate。設置該值會影響效率,若是內存過大,可能會消耗過長時間。
使用上面的代碼進行測試。建立一個新的cgroup test4且設置其memory.move_charge_at_immigrate=1。test1,test2和test3啓用use_hierarchy功能,限定內存上限爲100M
# cat memory.use_hierarchy 1 # cat memory.limit_in_bytes 104857600 # cat memory.memsw.limit_in_bytes 104857600
新的cgroup組織以下:
root / \ / \ test1 test4 / \ / \ test2 test3
使用程序t2申請30M內存,將其加入test2 tasks中,此時在test1 cgroup中能夠看到其使用的內存約30M;使用t3申請80M內存,固然此時t3沒法加入test3的tasks中。將t2遷移到test4 cgroup中,查看test1 cgroup的內存使用,其變爲了0
# cat memory.usage_in_bytes 0
此時將t3加入test3 cgroup,加入成功,查看test1 cgroup的內存使用,使用約80M,而test4 cgroup的內存使用約30M
# cat memory.usage_in_bytes 83894272
memory.oom_control用於控制oom-kill的行爲,默認啓動oom-kill,當內存不足時,oom-kill可能會進行內存回收。設置memory.oom_control=1時disable oom-kill,此時當進程監測到內存不足時會進入掛起或睡眠狀態
仍然使用上述代碼建立t1,申請100M內存,同時設置memory.oom_control=1,將其加入test1 cgroup,在t1申請內存以前,能夠看到其進程狀態爲S+
# ps -aux|grep test1
...
root 21382 0.0 0.0 4212 356 pts/11 S+ 23:24 0:00 ./test1
t1申請內存,能夠看到其進程狀態變爲了D+。能夠經過釋放test1 cgroup的內存(殺死或轉移其餘進程)或擴大內存上限(如echo 200M > memory.memsw.limit_in_bytes)來從新激活t1進程
# ps -aux|grep test1 ... root 21382 0.1 10.2 116856 102520 pts/11 D+ 23:24 0:00 ./test1
cgroup.event_control用來與memory.oom_control配合,在觸發oom-kill的時候給出事件通知。事件級別有low,medium和critical三種,事件傳遞有default,hierarchy,local三種示例代碼能夠參考memory_example-usage,該代碼運行時,當cgroup的內存觸發oom-kill的時候會給出"mem_cgroup oom event received"的提示。
TIPs:
參考:
https://segmentfault.com/a/1190000006917884
http://man7.org/linux/man-pages/man7/cgroups.7.html
http://www.haifux.org/lectures/299/netLec7.pdf
https://files-cdn.cnblogs.com/files/lisperl/cgroups%E4%BB%8B%E7%BB%8D.pdf
https://www.cnblogs.com/AlwaysOnLines/p/5639713.html
https://www.cnblogs.com/wuchanming/p/4465155.html
https://github.com/digoal/blog/blob/master/201701/20170111_02.md
http://linuxperf.com/?cat=7