红联Linux门户
Linux帮助

Linux系统监控-内存读取

发布时间:2017-03-25 11:38:11来源:linux网站作者:staticnetwind
一、背景
做一个监控程序,监控设备系统使用内存情况;后续使用 free命令发现系统内存越来越小,而小到一定程度后仍然保持,并未导致OOM。
 
二、相关资料
Linux 下 free 命令手册
NAME
free - Display amount of free and used memory in the system
SYNOPSIS
free [-b | -k | -m] [-o] [-s delay ] [-t] [-V]
DESCRIPTION
free  displays the total amount of free and used physical and swap memory in the system, as well as the buffers used by the kernel.  The shared memory col-
umn should be ignored; it is obsolete.
Options
The -b switch displays the amount of memory in bytes; the -k switch (set by default) displays it in kilobytes; the -m switch displays it in megabytes.
The -t switch displays a line containing the totals.
The -o switch disables the display of a "buffer adjusted" line.  If the -o option is not specified, free subtracts buffer memory from the used  memory  and
adds it to the free memory reported.
The  -s  switch  activates  continuous  polling  delay  seconds  apart. You may actually specify any floating point number for delay, usleep(3) is used for
microsecond resolution delay times.
The -V displays version information.
执行效果为:
1
从第一行Mem上看,当前系统总内存1024M,从内存使用上看已经使用1010M,剩余空闲内存13.8M,但实际上是这样的吗?
搜索了下 buffers 和 cached 的概念,得到:
A buffer is something that has yet to be "written" to disk. 
A cache is something that has been "read" from the disk and stored for later use.
查看-/+ buffers/cache 这一行看出,考虑 buffers cached 后,实际系统使用内存 = used -buffers + cached;实际系统空闲内存 = free + buffers + cached;
通过源码 procps-3.2.8/free.c 看出计算方法:
if(!old_fmt){
unsigned KLONG buffers_plus_cached = kb_main_buffers + kb_main_cached;
printf(
"-/+ buffers/cache: %10Lu %10Lu\n", 
S(kb_main_used - buffers_plus_cached),
S(kb_main_free + buffers_plus_cached)
);  
}
其中 kb_main_buffers,kb_main_cached 通过读取/proc/meminfo 得到
然而有的同学反映他们的 free 命令并未包含 cached 项,查了下是busybox下的代码,计算的公式被简化为 空闲内存 = free + buffers
printf("Mem: ");
printf(FIELDS_5,
scale(info.totalram),
scale(info.totalram - info.freeram),
scale(info.freeram),
scale(info.sharedram),
scale(info.bufferram)
);  
/* Show alternate, more meaningful busy/free numbers by counting
* buffer cache as free memory (make it "-/+ buffers/cache"
* if/when we add support for "cached" column): */
printf("-/+ buffers:      ");
printf(FIELDS_2,
scale(info.totalram - info.freeram - info.bufferram),
scale(info.freeram + info.bufferram)
);
其中,info结构体通过 sysinfo() 调用得到,但并没有考虑到 cache 的影响;
 
三、总结
对于应用程序来讲,可以使用的空间应该考虑上 buffer cache 和 page cache,前者是linux做磁盘缓存,后者是做文件inode缓存使用。
实践上看,虽然高IO负荷运行的设备所剩的 free 空间不足,但可以发现一部分是由 buffer 和 cache 所占用的,并不会导致程序申请空间失败。
所以结合 sysinfo接口和 /proc/meminfo 读取的方式,计算当前使用内存。
typedef struct system_t
{
u64 uptime;
u32 mem_size;
u32 mem_free;
u32 mem_used;
u32 mem_buffer;
u32 mem_cached;
u32 mem_shared;
double mem_usage;
} system_t;
int get_system_mem(system_t *psys)
{
int ret = FAILURE;
struct sysinfo info = {0};
char line[SIZE_LINE_NORMAL] = {0};
FILE *fp = NULL;
if ( !psys ) { 
LOGW("NULL\n");
goto _E1;
}   
fp = fopen("/proc/meminfo", "r");
if ( !fp ) { 
ret = FAILURE;
goto _E1;
}   
while ( fgets(line, SIZE_LINE_NORMAL, fp) ) { 
if ( 1 == sscanf(line, "Cached:\t%u %*s", &psys->mem_cached) ) { 
break;
}   
}   
CLOSE_FILE(fp);
ret = sysinfo(&info);
if ( SUCCESS != ret ) { 
goto _E1;
}   
/* byte to Kbyte */
psys->uptime     = info.uptime;
psys->mem_size   = info.totalram >> 10;
psys->mem_shared = info.sharedram >> 10;
psys->mem_buffer = info.bufferram >> 10;<pre name="code" class="cpp">    psys->mem_usage  = (double)(100 * psys->mem_used) / psys->mem_size;
ret = SUCCESS;
_E1:
return ret;
}
一个检测的内存不足的监控例子,当出现使用超过80%的时候进行返回错误;考虑内存总量不变的情况,使用静态变量进行存储;
int check_system_mem()
{
int ret = -1;
int ix = 0;
struct sysinfo info = {0};
char line[32] = {0};
FILE *fp = NULL;
static unsigned int mem_limit;
unsigned int mem_cached = 0;
unsigned int mem_buffer = 0;
unsigned int mem_free   = 0;
if ( mem_limit == 0 ) { 
ret = sysinfo(&info);
if ( 0 != ret ) { 
return -1; 
}   
/* Bytes to KBytes, 20% free limited */
mem_limit = (info.totalram * 0.2) / 1024;
}   
fp = fopen("/proc/meminfo", "r");
if ( !fp ) { 
return -1;
}
/* Scanf first 4 lines */
for ( ix = 0; fgets(line, sizeof(line), fp) && ix < 4; ix++ ) {
if ( 1 == sscanf(line, "MemFree:\t%u %*s", &mem_free) ) {
continue;
}
else if ( 1 == sscanf(line, "Buffers:\t%u %*s", &mem_buffer) ) {
continue;
}
else if ( 1 == sscanf(line, "Cached:\t%u %*s", &mem_cached) ) {
continue;
}
}
fclose(fp);
fp = NULL;
ret = ( (mem_free + mem_buffer + mem_cached) < mem_limit ) ? -1: 0;
return ret;
}
 
本文永久更新地址:http://www.linuxdiyf.com/linux/29475.html