通过获取Linux中的 /proc/stat 文件中的内容可以获取系统内存的详细信息:

  1. # cat /proc/meminfo
  2. MemTotal: 3880404 kB
  3. MemFree: 3182248 kB
  4. MemAvailable: 3396580 kB
  5. Buffers: 39588 kB
  6. Cached: 355616 kB
  7. SwapCached: 0 kB
  8. Active: 318708 kB
  9. Inactive: 252380 kB
  10. Active(anon): 176120 kB
  11. Inactive(anon): 248 kB
  12. Active(file): 142588 kB
  13. Inactive(file): 252132 kB
  14. Unevictable: 0 kB
  15. Mlocked: 0 kB
  16. SwapTotal: 0 kB
  17. SwapFree: 0 kB
  18. Dirty: 0 kB
  19. Writeback: 0 kB
  20. AnonPages: 175940 kB
  21. Mapped: 54184 kB
  22. Shmem: 488 kB
  23. Slab: 62040 kB
  24. SReclaimable: 48712 kB
  25. SUnreclaim: 13328 kB
  26. KernelStack: 2672 kB
  27. PageTables: 6080 kB
  28. NFS_Unstable: 0 kB
  29. Bounce: 0 kB
  30. WritebackTmp: 0 kB
  31. CommitLimit: 1940200 kB
  32. Committed_AS: 615340 kB
  33. VmallocTotal: 34359738367 kB
  34. VmallocUsed: 14160 kB
  35. VmallocChunk: 34359715580 kB
  36. HardwareCorrupted: 0 kB
  37. AnonHugePages: 36864 kB
  38. CmaTotal: 0 kB
  39. CmaFree: 0 kB
  40. HugePages_Total: 0
  41. HugePages_Free: 0
  42. HugePages_Rsvd: 0
  43. HugePages_Surp: 0
  44. Hugepagesize: 2048 kB
  45. DirectMap4k: 53120 kB
  46. DirectMap2M: 3092480 kB
  47. DirectMap1G: 3145728 kB

各字段含义见下表:

指标 作用
MemTotal 总内存大小
MemFree 空闲内存大小
buffers/cached 磁盘缓存的大小
MemAvailable 可用内存大小
SwapTotal 可用的swap空间的总的大小。
SwapFree 剩余swap空间的大小。
Dirty 需要写入磁盘的内存区大小。
Writeback 正在被写回磁盘的大小。
AnonPages 未映射页的内存大小。
Mapped 设备和文件等映射的大小。
Slab 内核数据结构slab的大小,可以减少申请和释放内存带来的消耗。

注Buffers 和 Cached的区别

Buffers 是指用来给块设备做的缓冲大小,他只记录文件系统的metadata以及 tracking in-flight pages. cached 是用来给文件做缓冲。

buffers 是值存储目录里面有什么内容,权限等等。 而cached直接用来记忆我们打开的文件,比如先后执行两次命令#man X ,你就可以明显的感觉到第二次的开打的速度快很多。 而buffers随时都在增加,比如先后两次使用ls /dev后,就会发现第二次执行的速度会较第一次快。 这就是buffers/chached的区别。

  • 以内核态来讲, bufferscached 是已经被使用的,可用内存就是 MemAvailable

    1. MemUsed = MemTotal - MemFree
  • 以用户态来讲,bufferscached 可被分配。

    1. free = MemFree + Buffers + Cahched
  • 本着监控应用对物理内存使用情况的目的采集,计算方法:

    1. MemUsedPrec = 100*(MemTotal - MemFree - Buffers - Cahched)/MemTotal

黑洞

计算 Linux 内存使用率方法及C实现 - 图1 经过一番计算,发现 /proc/meminfo 中的数据无论如何无法与 free 中的内容对应,尤其是在 used 部分。经过一番信息检索,得出一个结论, free 命令中的数值是按照 /proc/meminfo 中的数据,根据一定算法计算所得,并且新版旧版的 free 所输出内容也不一致。因此按照 proc/meminfo 中的数据计算内存使用率是更加精确的。
进一步探索,会发现 Linux 存在一个内存黑洞,在某博主博客找到如下描述:

追踪Linux系统的内存使用一直是个难题,很多人试着把能想到的各种内存消耗都加在一起,kernel text、kernel modules、buffer、cache、slab、page table、process RSS…等等,却总是与物理内存的大小对不上,这是为什么呢?因为Linux kernel并没有滴水不漏地统计所有的内存分配,kernel动态分配的内存中就有一部分没有计入/proc/meminfo中。 —— 《/PROC/MEMINFO之谜

综上原因,计算Linux内存使用率也就没有必要去细扣每个数值的含义了,大致了解如下内容即可:

  • MemTotal:总内存大小
  • MemFree: 空闲内存大小
  • buffers/cached: 磁盘缓存的大小
  • MemAvailable: 可用内存大小

而计算内存使用率只需按照这个方法计算:

  1. 实际可挪用的内存数: free+cache+buffer,
  2. 实际可使用的内存数: used-cache-buffer (total-free-cache-buffer)。
  3. 内存占用率:(total-available) / total * 100

C实现

同样的, 先定义一个结构体用于存放相关数据:

  1. struct MEM_INFO
  2. {
  3. unsigned int total;
  4. unsigned int free;
  5. unsigned int buffers;
  6. unsigned int cached;
  7. unsigned int swap_cached;
  8. unsigned int swap_total;
  9. unsigned int swap_free;
  10. unsigned int available;
  11. };
  12. typedef struct MEM_INFO Mem_info;

之后定义函数,用于获取及计算内存数据:

  1. void get_mem_occupy (Mem_info *o)
  2. {
  3. FILE* fpMemInfo = fopen("/proc/meminfo", "r");
  4. if (NULL == fpMemInfo)
  5. {
  6. return ;
  7. }
  8. int i = 0;
  9. int value;
  10. char name[1024];
  11. char line[1024];
  12. int nFiledNumber = 2;
  13. int nMemberNumber = 5;
  14. while (fgets(line, sizeof(line) - 1, fpMemInfo))
  15. {
  16. if (sscanf(line, "%s%u", name, &value) != nFiledNumber)
  17. {
  18. continue;
  19. }
  20. if (0 == strcmp(name, "MemTotal:"))
  21. {
  22. ++i;
  23. o->total = value;
  24. }
  25. else if (0 == strcmp(name, "MemFree:"))
  26. {
  27. ++i;
  28. o->free = value;
  29. }
  30. else if (0 == strcmp(name, "MemAvailable:"))
  31. {
  32. ++i;
  33. o->available = value;
  34. }
  35. else if (0 == strcmp(name, "Buffers:"))
  36. {
  37. ++i;
  38. o->buffers = value;
  39. }
  40. else if (0 == strcmp(name, "Cached:"))
  41. {
  42. ++i;
  43. o->cached = value;
  44. }
  45. if (i == nMemberNumber)
  46. {
  47. break;
  48. }
  49. }
  50. // system("free");
  51. // system("cat /proc/meminfo");
  52. // printf("MemTotal : %d\n",o->total);
  53. // printf("MemFree : %d\n",o->free);
  54. // printf("MemAvailable : %d\n",o->available);
  55. // printf("MemBuffers : %d\n",o->buffers);
  56. // printf("MemCached : %d\n",o->cached);
  57. // printf("MemSwapCached : %d\n",o->swap_cached);
  58. // printf("MemSwapTotal : %d\n",o->swap_total);
  59. // printf("MemSwapFree : %d\n",o->swap_free);
  60. fclose(fpMemInfo);
  61. }
  62. float cal_mem_occupy(Mem_info *o)
  63. {
  64. return (100.0 * (o->total - o->available) / o->total);
  65. }

最后调用即可:

  1. Mem_info omem;
  2. while(1)
  3. {
  4. // printf("-------------------- Mem occupy -------------------\n");
  5. get_mem_occupy(&omem);
  6. printf("Mem Usage(%): %8.4f\n", cal_mem_occupy(&omem));
  7. printf("\n");
  8. }

参考文献