聲明:如需引用或者摘抄本博文源碼或者其文章的,請在顯著處注明,來源於本博文/作者,以示尊重勞動成果,助力開源精神。也歡迎大家一起探討,交流,以共同進步,乃至成為朋友~ 0.0
/*
@url:http://www.cnblogs.com/johnnyzen/p/8011309.html
@author:Johnny Zen
@school:XiHua University
@contact:johnnyztsd@gmail.com or 1125418540@qq.com
@date:2017-12-10 13:47
@description:內存計算與辨析
@environment:Linux For Ubuntu 16.04/64
*/
計算內存利用率的引導思路
1.手動查看內存(的各參數)狀況
cat /proc/meminfo
其中有如下重點參數:
MemTotal:總內存大小
MemFree: 系統空閑內存大小,表示系統尚未使用的內存
MemAvailable:應用程序可用內存數,應用程序可用內存數。內存可獲得/可使用的存儲量(注意:3.14內核新增功能)
官網解釋:
Many load balancing and workload placing programs check /proc/meminfo to estimate how much free memory is available. They generally do this by adding up "free" and "cached", which was fine ten years ago, but is pretty much guaranteed to be wrong today.
It is wrong because Cached includes memory that is not freeable as page cache, for example shared memory segments, tmpfs, and ramfs, and it does not include reclaimable slab memory, which can take up a large fraction of system memory on mostly idle systems with lots of files.Currently, the amount of memory that is available for a new workload,without pushing the system into swap, can be estimated from MemFree, Active(file), Inactive(file), and SReclaimable, as well as the "low"watermarks from /proc/zoneinfo.However, this may change in the future, and user space really should not be expected to know kernel internals to come up with an estimate for the amount of free memory.It is more convenient to provide such an estimate in /proc/meminfo. If things change in the future, we only have to change it in one place.
翻譯過來:
許多負載均衡和負載放置程序檢查/proc/meminfo估計多少空閑內存。他們通常通過增加“內存自由區”和“內存緩存區”來實現這一點,這在十年前是很好的,但今天肯定是錯誤的。
因為緩存包含內存不可用的頁面緩存,例如共享內存段,tmpfs,和ramfs,它不包含可回收板內存,這會占用系統內存很大一部分主要包含大量文件的怠速系統。目前,這是一個新的工作量內存量,不推系統互換,可以估算工具,積極的(文件),無效(文件),並sreclaimable,以及從/ proc / zoneinfo.however“低”的水印,這可能會在未來改變,與用戶空間真的不應該知道內核到拿出空閑內存量的估算。它是提供在/proc/meminfo這樣的估計更方便。如果事情在未來發生變化,我們只需要在一個地方改變它。
即:[引用自博文 [Linux MemFree與MemAvailable的區別]:http://www.th7.cn/system/lin/201708/226350.shtml]
系統中有些內存雖然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收,所以MemFree不能代表全部可用的內存,這部分可回收的內存加上MemFree才是系統可用的內存,即:MemAvailable≈MemFree+Buffers+Cached,它是內核使用特定的算法計算出來的,是一個估計值。它與MemFree的關鍵區別點在於,MemFree是說的系統層面,MemAvailable是說的應用程序層面。
實際意義:
MemAvailable:MemFree+Active(file)+Inactive(file)-(watermark+min(watermark,Active(file)+Inactive(file)/2))
Buffers:磁盤緩沖大小
Cached:磁盤緩存大小
2.計算內存利用率公式
MemUsed(內存(已)使用量) = MemTotal(內存總存儲量) - MemAvailable(內存可獲得/可使用的存儲量)
注意:
需要注意的是,網絡上有很多"誤導"(其實,也不是誤導,只是站在不同的使用角度(操作系統/應用程序(用戶))來說而已)教程,他們是如此認為的:
定義:MemUsed(內存(已)使用量,不可直接算出,根據不同的使用角度/概念,計算出的結果不一致)
這里有什么"誤導"呢?
首先,要明白MemFree(內存空閑的存儲量)是怎么計算出來的:
對【操作系統】來說,Buffers和Cached是被視為【已經被使用】的:
原理:
MemUsed(內存(已)使用量,包含:Buffers,Cached) = MemTotal(內存總存儲量) - MemFree(內存空閑的存儲量)【結果將偏高】
MemFree = MemTotal - MemUsed(包含:Buffers,Cached) 【結果將偏低】
或者,這樣看:
對【應用程序】來說,Buffers和Cached是被視為【未被使用】的:
解釋:cache屬於OS管理,對應用程序是透明的
原理:
free(重定義) = MemAvailable
MemUsed = MemTotal - MemAvailable
3.實際使用
理解[2]以后,就很好辦了:根據編程用戶的實際需要,計算內存利用情況
以【應用程序/系統內用戶】的角度:
內存使用率MemUsedPencentage = (MemTotal - MemAvailable) * 100
Eg:
Free = MemAvailable = 5595176 KB
MemUsed = 8087460 KB - 5595176 KB = 2492284 KB
MemUsedPencentage = ( MemUsed / MemTotal ) * 100 = 30.816647(%)
4.驗證
打開Linux For Ubuntu 系統檢測查看
[公式計算的數據屬於歷史數據,所以與上式計算結果有出入。下圖中的是實時截圖數據,其左側,屬於【用戶角度/應用程序】計算的內存利用率結果,其右側屬於【操作系統角度】所上計算出的內存利用率結果]

5.編程實現
/*
@url:http://www.cnblogs.com/johnnyzen/p/8011309.html
@author:Johnny Zen
@school:XiHua University
@contact:johnnyztsd@gmail.com or 1125418540@qq.com
@date:2017-12-10 14:53
@description:本程序分別計算從【操作系統/用戶角度】計算出的內存利用情況
@environment:Linux For Ubuntu 16.04/64
/
關於[內存利用率的計算與辨析]已寫入個人博客,詳見:
[Linux之計算內存利用率與辨析 ]http://www.cnblogs.com/johnnyzen/p/8011309.html
關於[Linux虛擬文件系統/proc的概述性理解]也已寫入個人博客,詳見:
[Linux之虛擬文件系統[/proc]中關於CPU/內存/網絡/內核等的一些概要性說明]:http://www.cnblogs.com/johnnyzen/p/8011374.html
/
*/
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MemTotal_LINE_NUMBER 1 //內存【總存儲空間】所處行數
#define MemFree_LINE_NUMBER 2 //【內存空閑存儲空間數據】(對於應用程序)所處行數
#define MemAvailable_LINE_NUMBER 3 //【應用程序可利用】的內存存儲空間數所處行數
//[注意:MemAvailable_LINE_NUMBER 必須大於 MemTotal_LINE_NUMBER,否則讀取數據處代碼將會產生讀取數據失敗等異常結果]
//參數:TYPE:["SYSTEM_NUMMERIC/SYSTEM_PERCENTAGE/APPLiCATION_NUMMERIC/APPLiCATION_PERCENTAGE"]
float mem_usage(char * TYPE){
FILE *mem_stream;
char mem_buffer[256];//緩沖區
char memTotal_line[256];//內存總數
char memFree_line[256]; //空閑內存數
char file[64] = {"/proc/meminfo"};//要讀取的目標文件名
mem_stream = fopen (file, "r"); //以R讀的方式打開文件再賦給指針fd
char tmp_itemName[32];//臨時存放文件中的項目名稱
int memTotal;//存放內存總數(單位:KB)
int memFree; //存放空閑內存數(單位:KB)
int memAvailable;//存放應用程序的可利用內存存儲空間大小(單位:KB)
int memUsed;
//計算已經使用的內存(數值)(分別從用戶/應用程序(memAvailable)角度或者操作系統(memFree)角度計算)
float result; //函數返回值
//讀取數據
char *line_return;//記錄讀取每行的時候的返回結果(NULL或者返回mem_buffer)
for(int i = 0; i < MemAvailable_LINE_NUMBER; i++){
line_return = fgets (mem_buffer, sizeof(mem_buffer), mem_stream);
if(i == (MemTotal_LINE_NUMBER -1)){
if(line_return != NULL){//讀取成功
sscanf(mem_buffer, "%s%d", tmp_itemName, &memTotal);
} else {
printf("[mem_usage] Read File in line %d Fail!", MemTotal_LINE_NUMBER);
exit(1);
}
} else if(i == (MemFree_LINE_NUMBER - 1)) {
if(line_return != NULL){//讀取成功
sscanf(mem_buffer, "%s%d", tmp_itemName, &memFree);
} else {
printf("[mem_usage] Read File in line %d Fail!", MemFree_LINE_NUMBER);
exit(1);
}
} else if(i == (MemAvailable_LINE_NUMBER - 1)){
if(line_return != NULL){//讀取成功
sscanf(mem_buffer, "%s%d", tmp_itemName, &memAvailable);
} else {
printf("[mem_usage] Read File in line %d Fail!", MemAvailable_LINE_NUMBER);
exit(1);
}
}
}
fclose(mem_stream); //關閉文件mem_stream
if(TYPE == "SYSTEM_NUMMERIC"){
memUsed = memTotal - memFree;
result = memUsed;
} else if(TYPE == "SYSTEM_PERCENTAGE"){
memUsed = memTotal - memFree;
result = (((float) memUsed / (float)memTotal) * 100);
} else if(TYPE == "APPLiCATION_NUMMERIC"){
memUsed = memTotal - memAvailable;
result = memUsed;
} else if(TYPE == "APPLiCATION_PERCENTAGE"){
memUsed = memTotal - memAvailable;
result = (((float) memUsed / (float)memTotal) * 100);
}
printf("\n[MEM] System memTotal: %d KB.\n", memTotal);
printf("[MEM] System memFree: %d KB.\n", memFree);
printf("[MEM] System memUsed: %d KB.\n", (memTotal - memFree));
printf("[MEM] APPLiCATION memUsed: %d KB.\n", (memTotal - memAvailable));
return result;
}
//demo
int main(){
printf("\n[MAIN MEM] MEM SYSTEM Usage PERCENTAGE: %.2f %s.\n\n",
mem_usage("SYSTEM_PERCENTAGE"), "%");
printf("\n[MAIN MEM] MEM SYSTEM Total Used Usage: %.2f %s.\n\n",
mem_usage("SYSTEM_NUMMERIC"), "KB");
printf("\n[MAIN MEM] MEM APPLiCATION Usage PERCENTAGE: %.2f %s.\n\n",
mem_usage("APPLiCATION_PERCENTAGE"), "%");
printf("\n[MAIN MEM] MEM APPLiCATION Total Used Usage: %.2f %s.\n\n",
mem_usage("APPLiCATION_NUMMERIC"), "KB");
return 0;
}
運行效果:

參考文獻:
[proc/meminfo 文件內存詳解]:http://blog.csdn.net/u014089131/article/details/52814516
[linux 計算內存使用率]:http://blog.csdn.net/u010807846/article/details/40919393(博主認為,其觀點不盡是全正確的,例如最后的結論,但仍有很多可取的觀點)
[Linux MemFree與MemAvailable的區別]:http://www.th7.cn/system/lin/201708/226350.shtml
