zoukankan      html  css  js  c++  java
  • [C++]Linux之计算内存利用率与辨析

    声明:如需引用或者摘抄本博文源码或者其文章的,请在显著处注明,来源于本博文/作者,以示尊重劳动成果,助力开源精神。也欢迎大家一起探讨,交流,以共同进步,乃至成为朋友~ 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("
    [MEM] System memTotal: %d KB.
    ", memTotal);	
    	printf("[MEM] System memFree: %d KB.
    ", memFree);	
    	printf("[MEM] System memUsed: %d KB.
    ", (memTotal - memFree));	
    	printf("[MEM] APPLiCATION memUsed: %d KB.
    ", (memTotal - memAvailable));	
    
    	return result;
    }
    
    
    
    	//demo
    	int main(){
    
    		printf("
    [MAIN MEM] MEM SYSTEM Usage PERCENTAGE: %.2f %s.
    
    ", 
    			mem_usage("SYSTEM_PERCENTAGE"), "%");
    		printf("
    [MAIN MEM] MEM SYSTEM Total Used Usage: %.2f %s.
    
    ", 
    			mem_usage("SYSTEM_NUMMERIC"), "KB");
    		printf("
    [MAIN MEM] MEM APPLiCATION Usage PERCENTAGE: %.2f %s.
    
    ", 
    			mem_usage("APPLiCATION_PERCENTAGE"), "%");
    		printf("
    [MAIN MEM] MEM APPLiCATION Total Used Usage: %.2f %s.
    
    ", 
    			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

  • 相关阅读:
    批量修改文件的名字
    字节码指令以及操作数栈的分析
    字节码文件的分析
    类加载器详解
    类的加载-连接-初始化
    电商订单ElasticSearch同步解决方案--使用logstash
    springboot整合Mangodb实现crud,高级查询,分页,排序,简单聚合
    mongodb安装教程(亲测有效)
    Azure : 通过 SendGrid 发送邮件
    用java实现删除目录
  • 原文地址:https://www.cnblogs.com/johnnyzen/p/8011309.html
Copyright © 2011-2022 走看看