From: http://hustcat.github.io/about/

Linux中进程内存与cgroup内存的统计

在Linux内核,对于进程的内存使用与Cgroup的内存使用统计有一些相同和不同的地方。

进程的内存统计

一般来说,业务进程使用的内存主要有以下几种情况:

(1)用户空间的匿名映射页(Anonymous pages in User Mode address spaces),比如调用malloc分配的内存,以及使用MAP_ANONYMOUS的mmap;当系统内存不够时,内核可以将这部分内存交换出去;

(2)用户空间的文件映射页(Mapped pages in User Mode address spaces),包含map file和map tmpfs;前者比如指定文件的mmap,后者比如IPC共享内存;当系统内存不够时,内核可以回收这些页,但回收之前可能需要与文件同步数据;

(3)文件缓存(page in page cache of disk file);发生在程序通过普通的read/write读写文件时,当系统内存不够时,内核可以回收这些页,但回收之前可能需要与文件同步数据;

(4)buffer pages,属于page cache;比如读取块设备文件。

其中(1)和(2)是算作进程的RSS,(3)和(4)属于page cache。

与进程内存统计相关的几个文件:

  1. /proc/[pid]/stat
  2. (23) vsize %lu
  3. Virtual memory size in bytes.
  4. (24) rss %ld
  5. Resident Set Size: number of pages the process has
  6. in real memory. This is just the pages which count
  7. toward text, data, or stack space. This does not
  8. include pages which have not been demand-loaded in,
  9. or which are swapped out.

RSS的计算:

对应top的RSS列,do_task_stat

  1. #define get_mm_rss(mm) \
  2. (get_mm_counter(mm, file_rss) + get_mm_counter(mm, anon_rss))

即RSS=file_rss + anon_rss

  • /proc/[pid]/statm
  1. Provides information about memory usage, measured in pages.
  2. The columns are:
  3. size (1) total program size
  4. (same as VmSize in /proc/[pid]/status)
  5. resident (2) resident set size
  6. (same as VmRSS in /proc/[pid]/status)
  7. share (3) shared pages (i.e., backed by a file)
  8. text (4) text (code)
  9. lib (5) library (unused in Linux 2.6)
  10. data (6) data + stack
  11. dt (7) dirty pages (unused in Linux 2.6)

见函数proc_pid_statm

  1. int task_statm(struct mm_struct *mm, int *shared, int *text,
  2. int *data, int *resident)
  3. {
  4. *shared = get_mm_counter(mm, file_rss);
  5. *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK))
  6. >> PAGE_SHIFT;
  7. *data = mm->total_vm - mm->shared_vm;
  8. *resident = *shared + get_mm_counter(mm, anon_rss);
  9. return mm->total_vm;
  10. }

top的SHR=file_rss。实际上,进程使用的共享内存,也是算到file_rss的,因为共享内存基于tmpfs。

anon_rss与file_rss的计算

  1. static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
  2. unsigned long address, pmd_t *pmd,
  3. pgoff_t pgoff, unsigned int flags, pte_t orig_pte)
  4. {
  5. if (flags & FAULT_FLAG_WRITE) {
  6. if (!(vma->vm_flags & VM_SHARED)) {
  7. anon = 1;///anon page
  8. ...
  9. if (anon) {
  10. inc_mm_counter(mm, anon_rss);
  11. page_add_new_anon_rmap(page, vma, address);
  12. } else {
  13. inc_mm_counter(mm, file_rss);
  14. page_add_file_rmap(page);

cgroup 的内存统计

stat file

memory.stat file includes following statistics

  1. # per-memory cgroup local status
  2. cache - # of bytes of page cache memory.
  3. rss - # of bytes of anonymous and swap cache memory (includes
  4. transparent hugepages).
  5. rss_huge - # of bytes of anonymous transparent hugepages.
  6. mapped_file - # of bytes of mapped file (includes tmpfs/shmem)
  7. pgpgin - # of charging events to the memory cgroup. The charging
  8. event happens each time a page is accounted as either mapped
  9. anon page(RSS) or cache page(Page Cache) to the cgroup.
  10. pgpgout - # of uncharging events to the memory cgroup. The uncharging
  11. event happens each time a page is unaccounted from the cgroup.
  12. swap - # of bytes of swap usage
  13. dirty - # of bytes that are waiting to get written back to the disk.
  14. writeback - # of bytes of file/anon cache that are queued for syncing to
  15. disk.
  16. inactive_anon - # of bytes of anonymous and swap cache memory on inactive
  17. LRU list.
  18. active_anon - # of bytes of anonymous and swap cache memory on active
  19. LRU list.
  20. inactive_file - # of bytes of file-backed memory on inactive LRU list.
  21. active_file - # of bytes of file-backed memory on active LRU list.
  22. unevictable - # of bytes of memory that cannot be reclaimed (mlocked etc).

相关代码

  1. static void
  2. mem_cgroup_get_local_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
  3. {
  4. s64 val;
  5. /* per cpu stat */
  6. val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_CACHE);
  7. s->stat[MCS_CACHE] += val * PAGE_SIZE;
  8. val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
  9. s->stat[MCS_RSS] += val * PAGE_SIZE;
  10. val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_FILE_MAPPED);
  11. s->stat[MCS_FILE_MAPPED] += val * PAGE_SIZE;
  12. val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT);
  13. s->stat[MCS_PGPGIN] += val;
  14. val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT);
  15. s->stat[MCS_PGPGOUT] += val;
  16. if (do_swap_account) {
  17. val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_SWAPOUT);
  18. s->stat[MCS_SWAP] += val * PAGE_SIZE;
  19. }
  20. /* per zone stat */
  21. val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_ANON);
  22. s->stat[MCS_INACTIVE_ANON] += val * PAGE_SIZE;
  23. val = mem_cgroup_get_local_zonestat(mem, LRU_ACTIVE_ANON);
  24. s->stat[MCS_ACTIVE_ANON] += val * PAGE_SIZE;
  25. val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_FILE);
  26. s->stat[MCS_INACTIVE_FILE] += val * PAGE_SIZE;
  27. val = mem_cgroup_get_local_zonestat(mem, LRU_ACTIVE_FILE);
  28. s->stat[MCS_ACTIVE_FILE] += val * PAGE_SIZE;
  29. val = mem_cgroup_get_local_zonestat(mem, LRU_UNEVICTABLE);
  30. s->stat[MCS_UNEVICTABLE] += val * PAGE_SIZE;
  31. }

数据结构

  1. struct mem_cgroup {
  2. ...
  3. /*
  4. * statistics. This must be placed at the end of memcg.
  5. */
  6. struct mem_cgroup_stat stat; ///统计数据
  7. };
  8. /* memory cgroup统计值
  9. * Statistics for memory cgroup.
  10. */
  11. enum mem_cgroup_stat_index {
  12. /*
  13. * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss.
  14. */
  15. MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */
  16. MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */
  17. MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */
  18. MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */
  19. MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */
  20. MEM_CGROUP_STAT_EVENTS, /* sum of pagein + pageout for internal use */
  21. MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */
  22. MEM_CGROUP_STAT_NSTATS,
  23. };
  24. struct mem_cgroup_stat_cpu {
  25. s64 count[MEM_CGROUP_STAT_NSTATS];
  26. } ____cacheline_aligned_in_smp;
  27. struct mem_cgroup_stat {
  28. struct mem_cgroup_stat_cpu cpustat[0];
  29. };
  30. rss and cache
  31. cache - # of bytes of page cache memory. rss - # of bytes of anonymous and swap cache memory (includes transparent hugepages).
  32. static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
  33. struct page_cgroup *pc,
  34. long size)
  35. {
  36. ...
  37. cpustat = &stat->cpustat[cpu];
  38. if (PageCgroupCache(pc))
  39. __mem_cgroup_stat_add_safe(cpustat,
  40. MEM_CGROUP_STAT_CACHE, numpages);
  41. else
  42. __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_RSS,
  43. numpages);
  44. static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
  45. struct page_cgroup *pc,
  46. enum charge_type ctype,
  47. int page_size)
  48. {
  49. switch (ctype) {
  50. case MEM_CGROUP_CHARGE_TYPE_CACHE:
  51. case MEM_CGROUP_CHARGE_TYPE_SHMEM: //file cache + shm
  52. SetPageCgroupCache(pc);
  53. SetPageCgroupUsed(pc);
  54. break;
  55. case MEM_CGROUP_CHARGE_TYPE_MAPPED:
  56. ClearPageCgroupCache(pc);
  57. SetPageCgroupUsed(pc);
  58. break;
  59. default:
  60. break;
  61. }
  62. ///更新统计值
  63. mem_cgroup_charge_statistics(mem, pc, page_size);
  64. int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
  65. gfp_t gfp_mask)
  66. {
  67. ...
  68. if (page_is_file_cache(page))
  69. return mem_cgroup_charge_common(page, mm, gfp_mask,
  70. MEM_CGROUP_CHARGE_TYPE_CACHE, NULL); ///file cache
  71. /* shmem */
  72. if (PageSwapCache(page)) {
  73. ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &mem);
  74. if (!ret)
  75. __mem_cgroup_commit_charge_swapin(page, mem,
  76. MEM_CGROUP_CHARGE_TYPE_SHMEM);
  77. } else
  78. ret = mem_cgroup_charge_common(page, mm, gfp_mask, ///shm memory
  79. MEM_CGROUP_CHARGE_TYPE_SHMEM, mem);
  80. 可以看到,cache包含共享内存和file cache
  81. mapped_file
  82. mapped_file - # of bytes of mapped file (includes tmpfs/shmem)
  83. void mem_cgroup_update_file_mapped(struct page *page, int val)
  84. {
  85. ... __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_FILE_MAPPED, val);
  86. __do_fault –> page_add_file_rmap –> mem_cgroup_update_file_mapped
  87. inactive_anon
  88. inactive_anon - # of bytes of anonymous and swap cache memory on inactive LRU list.
  89. static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
  90. struct page **pagep, enum sgp_type sgp, gfp_t gfp, int *fault_type)
  91. {
  92. ...
  93. lru_cache_add_anon(page);
  94. /**
  95. * lru_cache_add: add a page to the page lists
  96. * @page: the page to add
  97. */
  98. static inline void lru_cache_add_anon(struct page *page)
  99. {
  100. __lru_cache_add(page, LRU_INACTIVE_ANON);
  101. }
  102. 从这里可以看到,共享内存会增加到INACTIVE_ANON
  103. inactive_file
  104. inactive_file - # of bytes of file-backed memory on inactive LRU list.文件使用的page cache(不包含共享内存)
  105. static inline void lru_cache_add_file(struct page *page)
  106. {
  107. __lru_cache_add(page, LRU_INACTIVE_FILE);
  108. }
  109. add_to_page_cache_lru –> lru_cache_add_file.

示例程序

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include <unistd.h>
  6. #include <sys/stat.h>
  7. #include <sys/types.h>
  8. #include <sys/ipc.h>
  9. #include <sys/shm.h>
  10. #define BUF_SIZE 4000000000
  11. #define MYKEY 26
  12. int main(int argc,char **argv){
  13. int shmid;
  14. char *shmptr;
  15. if((shmid = shmget(MYKEY,BUF_SIZE,IPC_CREAT)) ==-1){
  16. fprintf(stderr,"Create Share Memory Error0m~Z%s\n\a",strerror(errno));
  17. exit(1);
  18. }
  19. if((shmptr =shmat(shmid,0,0))==(void *)-1){
  20. printf("shmat error!\n");
  21. exit(1);
  22. }
  23. memset(shmptr,'\0',1000000000);
  24. printf("sleep...\n");
  25. while(1)
  26. sleep(1);
  27. exit(0);
  28. }

执行程序前后,cgroup memory.stat的值:

  • 执行前:*
  1. # cat memory.stat
  2. cache 1121185792
  3. rss 23678976
  4. rss_huge 0
  5. mapped_file 14118912
  6. inactive_anon 1002643456
  7. active_anon 23687168
  8. inactive_file 46252032
  9. active_file 72282112
  • 执行后:*
  1. # cat memory.stat
  2. cache 2121187328
  3. rss 23760896
  4. rss_huge 0
  5. mapped_file 1014124544
  6. inactive_anon 2002608128
  7. active_anon 23736320
  8. inactive_file 46247936
  9. active_file 72286208

ipcs -m

0x0000001a 229380 root 0 4000000000 1

可以看到cgroup中,共享内存计算在cache、mapped_file、inactive_anon中。

小结

(1)进程rss与cgroup rss的区别

进程的RSS为进程使用的所有物理内存(file_rss+anon_rss),即Anonymous pages+Mapped apges(包含共享内存)。cgroup RSS为(anonymous and swap cache memory),不包含共享内存。两者都不包含file cache。

(2)cgroup cache包含file cache和共享内存。

参考

http://man7.org/linux/man-pages/man5/proc.5.html

https://www.kernel.org/doc/Documentation/cgroups/memory.txt

[转]Linux中进程内存与cgroup内存的统计的更多相关文章

  1. linux中进程控制

    1.进程标识 每个进程都有一个非负整型表示的唯一的进程ID.进程ID标识符总是唯一的.  虽然进程ID是唯一的,但某个ID被回收后,ID号是可以复用的. ID为0的进程通常是调度进程(其常常被称交换进 ...

  2. 【网络编程基础】Linux下进程通信方式(共享内存,管道,消息队列,Socket)

    在网络课程中,有讲到Socket编程,对于tcp讲解的环节,为了加深理解,自己写了Linux下进程Socket通信,在学习的过程中,又接触到了其它的几种方式.记录一下. 管道通信(匿名,有名) 管道通 ...

  3. Linux中进程控制块PCB-------task_struct结构体结构

    Linux中task_struct用来控制管理进程,结构如下: struct task_struct { //说明了该进程是否可以执行,还是可中断等信息 volatile long state; // ...

  4. 『学了就忘』Linux系统管理 — 82、Linux中进程的查看(ps命令)

    目录 1.ps命令介绍 2.ps aux命令示例 3.ps -le命令示例 4.pstree命令 1.ps命令介绍 ps命令是用来静态显示系统中进程的命令. 不过这个命令有些特殊,它部分命令的选项前不 ...

  5. 『学了就忘』Linux系统管理 — 83、Linux中进程的查看(top命令)

    目录 1.top命令介绍 2.top命令示例 3.top命令输出项解释 4.top命令常用的实例 1.top命令介绍 top命令是用来动态显示系统中进程的命令. [root@localhost ~]# ...

  6. Linux中进程的优先级

    Linux採用两种不同的优先级范围,一种是nice值.还有一种是实时优先级. 1.nice值 nice值得范围是-20~19,默认值是0. 越大的nice值意味着更低的优先级.也就是说nice值为-2 ...

  7. Linux 中进程的管理

    Linux 的进程信号 1  HUP  挂起 2  INT  中断 3 QUIT  结束运行 9 KILL 无条件终止 11 SEGV 段错误 15 TERM 尽可能终止 17 STOP 无条件终止运 ...

  8. 使用Visual VM 查看linux中tomcat运行时JVM内存

    前言:在生产环境中经常发生服务器内存溢出,假死或者线程死锁等异常,导致服务不可用.我们经常使用的解决方法是通过分析错误日记,然后去寻找代码到底哪里出现了问题,这样的方式也许会奏效,但是排查起来耗费时间 ...

  9. 关于Linux下进程间使用共享内存和信号量通信的时的编译问题

    今天在编译一个使用信号量实现进程同步时,出现了库函数不存在的问题.如下图 编译结果实际上是说,没include相应的头文件,或是头文件不存在(即系统不支持该库函数) 但我man shm_open是可以 ...

随机推荐

  1. web 开发之js---JS变量也要注意初始化

    原先以为js作为弱类型语言,变量的初始化没必要,但是: var text; text+="你好"; alert(text); 对话框弹出的内容是:"undefined你好 ...

  2. JavaScript基础 -- DOM

    一.DOM全称 文档对象模型(Document Object Model) 二.DOM是什么 DOM可以说是制作动态页面的强有力工具.DOM不是JavaScript语言的一部分,而是内置在浏览器中的一 ...

  3. iOS开发——基础篇——get和post请求的区别

    HTTP 定义了与服务器交互的不同方法,最常用的有4种,Get.Post.Put.Delete,如果我换一下顺序就好记了,Put(增),Delete(删),Post(改),Get(查),即增删改查,下 ...

  4. 并不对劲的[Noi2008]道路设计

    Time Limit: 20 Sec Memory Limit: 162 MB Submit: 931 Solved: 509 [Submit][Status][Discuss] Descriptio ...

  5. 关于flask的错误:ImportError: cannot import name 'Flask'

    刚开始接触flask,新创建后不能运行,报错如下图: 导致该错误有两种可能,没安装flask:文件名为flask. 可尝试如下两种方法解决: 方法一:若没安装过flask,则进入cmd,输入pip i ...

  6. 洛谷 P1328 生活大爆炸版石头剪刀布 —— 模拟

    题目:https://www.luogu.org/problemnew/show/P1328 直接模拟即可. 代码如下: #include<iostream> #include<cs ...

  7. E20180127-hm

    retain  vt. 保持; 留在心中,记住; 雇用; 付定金保留;

  8. wamp集成环境下帝国备份出错

    我在本地wamp环境下面使用帝国备份王时,报错信息如下: Parse error: syntaxerror, unexpected $end in D:wampwwwhuifuclassfunctio ...

  9. spring controller接口中,用pojo对象接收页面传递的参数,发现spring在对pojo对象赋值时,有一定顺序的问题

    1.我的项目中的实体类都继承了基类entityBase,里面封装了分页的一些属性,pageindex.pagesize.pagerownum等. 2.思路是页面可以灵活的传递分页参数,比如当前页pag ...

  10. 转 PHP - AJAX 与 PHP

    1. AJAX 被用于创建交互性更强的应用程序. AJAX PHP 实例 下面的实例将演示当用户在输入框中键入字符时,网页如何与 Web 服务器进行通信: 实例 尝试在输入框中输入一个名字,如:Ann ...