1. free

linux系统中,查看当前内存的使用情况,简便的方法是free命令,命令行中free -m,列出系统当前的可用内存、cache/buffer、swap相关信息。

free工具是procps项目提供的标准proc文件系统分析工具,通过读取分析/proc/meminfo,实时的反应当前系统的内存使用情况。项目主页:procps.sourceforge.net

free

2. 用户态程序中,利用sysinfo系统调用

如果想在程序中实时查看系统当前可用内存情况,可以利用的方法也是多样的。

1.如果是在用户态程序中查看,可以通过“system”系统调用,执行free命令,或是读取/proc/meminfo文件,再做文本处理。

2.当然1的方法不够直观,/proc/meminfo中的信息是系统利用proc文件系统的处理函数获得的,内核代码fs/proc/meminfo.c中实现的。 粗读代码可以发现struct sysinfo这个结构(include/linux/kernel.h中定义)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct sysinfo {
         long uptime;                    /* Seconds since boot */
         unsigned long loads[3];         /* 1, 5, and 15 minute load averages */
         unsigned long totalram;         /* Total usable main memory size */
         unsigned long freeram;          /* Available memory size */
         unsigned long sharedram;        /* Amount of shared memory */
         unsigned long bufferram;        /* Memory used by buffers */
         unsigned long totalswap;        /* Total swap space size */
         unsigned long freeswap;         /* swap space still available */
         unsigned short procs;           /* Number of current processes */
         unsigned short pad;             /* explicit padding for m68k */
         unsigned long totalhigh;        /* Total high memory size */
         unsigned long freehigh;         /* Available high memory size */
         unsigned int mem_unit;          /* Memory unit size in bytes */
         char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
};

可以看到该结构中定义了系统的内存使用情况。源码中查询sysinfo,发现有sysinfo这个系统调用,用于查询和获得系统信息。于是在用户态程序中可以采用如下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <unistd.h>
#include <linux/kernel.h>

int main()
{
    struct sysinfo sys_i;
    int err = sysinfo(&sys_i);
    printf("\n\nerror code is: %d\n", err);

    printf( "free mem:\t%ld\n"                                                                               
            "total mem:\t%ld\n"
            "buffer mem:\t%ld\n", 
            sys_i.freeram, sys_i.totalram, sys_i.bufferram 
          );  

    return 0;
}

编译并执行:

~$ gcc -o play test.c

对比执行结果与free的结果: sysinfo与free对比

3. 内核态程序中,利用do_sysinfo中的si_meminfo实现

在内核态中实现,我没有找到很好的方法。通过读代码,找到执行sysinfo系统调用的回调函数sys_sysinfo

1
SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info)

进一步宏展开SYSCALL_DEFINE1得到验证:

1
2
3
4
5
6
7
8
9
10
11
SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info)
{
         struct sysinfo val;
 
         do_sysinfo(&val);
 
         if (copy_to_user(info, &val, sizeof(struct sysinfo)))
                 return -EFAULT;
 
         return 0;
}

核心实现函数为do_sysinfo函数,该函数执行内容过多,为免除不必要操作,只利用与freeram相关的函数操作,即:si_meminfo函数。

1
2
3
4
5
6
7
8
9
10
void si_meminfo(struct sysinfo *val)
{
         val->totalram = totalram_pages;
         val->sharedram = 0;
         val->freeram = global_page_state(NR_FREE_PAGES);
         val->bufferram = nr_blockdev_pages();
         val->totalhigh = totalhigh_pages;
         val->freehigh = nr_free_highpages();
         val->mem_unit = PAGE_SIZE;
}

可以看到,sysinfo中的ram相关内容被赋值。写一个内核模块做测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/page.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("GuoHongwei");

static int sysinfo_init()
{
    struct sysinfo sys;
    // int err = do_sysinfo(&sys);

    si_meminfo(&sys);

    // printk("\n\nerror code is: %ld", err);
    printk("free mem is: %ld\n", (sys.freeram << (PAGE_SHIFT - 10)));

    return 0;
}

static void sysinfo_exit()
{
    printk("exit module sysinfo_test\n");
}

module_init(sysinfo_init);
module_exit(sysinfo_exit);

Makefile:
obj-m := sysinfo_test.o
KERNELDIR = /lib/modules/$(shell uname -r)/build                                                             
PWD := $(shell pwd)

default:
        make -C $(KERNELDIR) M=$(PWD) modules

clean:
        make -C $(KERNELDIR) M=$(PWD) clean

执行结果如下:

si_meminfo