内存使用量

内存 ( memory )是操作系统管理的一项重要资源,对 内存使用量 进行监控, 有助于提前发现内存问题,避免因内存耗尽而造成的故障。 此外,精准的 监控数据 也可用于应用程序 性能分析 以及更进一步的 性能优化

执行 free 命令便可查看 内存使用量

$ free
              total        used        free      shared  buff/cache   available
Mem:        8174924      806748     5777464       85768     1590712     6952528
Swap:       7999484           0     7999484

free 命令展示了 物理内存 以及交换内存使用量,指标说明见下节。

指标

Linux 内核负责统计内存使用量并暴露在 proc 伪文件系统中,路径是 /proc/meminfo 。 一般而言,需要重点关注的指标如下:

内存使用量指标(字节)
指标名 含义
total 物理内存总量
free 空闲内存(未使用)
buffers 内核缓冲区
cached 文件缓冲页
slab 内核 slab 数据结构
cache cached 以及 slab 之和
g_free 广义空闲内存
used 已使用内存
active 活跃内存
inactive 非活跃内存
available 可用内存

total

total 表示 物理内存总量 ,单位为 字节 ,对应 /proc/meminfoMemTotal 字段。

free

free 表示 空闲内存量 ,单位为 字节 , 对应 /proc/meminfoMemFree 字段。

buffers

buffers 表示 内核缓冲区 ,单位为 字节 ,对应 /proc/meminfoBuffers 字段。

cached

cached 表示 文件缓冲页 ,单位为 字节 ,对应 /proc/meminfoCached 字段。

slab

slab 表示 内核slab数据结构 ,单位为 字节 ,对应 /proc/meminfoSlab 字段。

cache

cachefree 命令中的 cache 相同,即 cached 以及 slab 之和:

\[cache = cached + slab\]

g_free

g_free 表示 广义空闲内存 ( generalized free ),单位为 字节 ,计算方式如下:

\[g\_free = free + buffers + cache\]

bufferscache 是系统为了提升性能而使用的缓存,内存紧张时可随时回收另做它用。 因此,这部分内存在某种意义上可以认为是空闲的,这就是 广义空闲内存 的由来。 在某些场景, g_freefree 更有参考价值。

used

used 表示 已用内存 ,单位为 字节 ,计算方式如下:

\[used = total - g\_free = total - free - buffers - cache\]

active

active 表示 活跃内存 ,单位为 字节 ,对应 /proc/meminfoActive 字段。

活跃内存 是指最近经常访问的内存,通常不会被重新分配,除非非常必要。

inactive

inactive 表示 非活跃内存 ,单位为 字节 ,对应 /proc/meminfoInactive 字段。

非活跃内存 是指最近较少访问的内存,需要新分配内存时,这部分优先选择。

available

available 表示 可用内存 ,单位为 字节 ,对应 /proc/meminfoMemAvailable 字段。

可用内存 指的是可用于启动一个新应用进程的内存,该指标是内核提供的一个估计值。 它同样结合 free 以及 cache 两部分内存,但是考虑到 cache 因使用而不能释放的情况。 因此,可以认为:

\[free \le available \le g\_free\]

采集

数据采集非常简单,读取 /proc/meminfo 文件相关字段即可:

memory_usage.py
 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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import json

UNIT_MAPPING = {
    'kB': 1024,
    'KB': 1024,
}


def parse_value(value):
    # default, no unit
    unit = ''

    # split value string
    parts = value.strip().split()
    if len(parts) == 2:
        number, unit = parts
    else:
        number, = parts

    return int(number.strip()) * UNIT_MAPPING.get(unit.strip(), -1)


def sample_memory_usage():
    # open data file
    with open('/proc/meminfo') as f:
        # open all lines
        lines = f.readlines()

        # split every line to a pair by :
        pairs = [
            line.strip().split(':', 1)
            for line in lines
        ]

        # data dict
        datas = {
            name.strip(): parse_value(value)
            for name, value in pairs
        }

        # calculate
        total = datas['MemTotal']
        free = datas['MemFree']
        buffers = datas['Buffers']
        cached = datas['Cached']
        slab = datas['Slab']
        cache = cached + slab
        g_free = free + buffers + cache
        used = total - g_free
        active = datas['Active']
        inactive = datas['Inactive']
        available = datas['MemAvailable']

        return {
            'total': total,
            'free': free,
            'buffers': buffers,
            'cached': cached,
            'slab': slab,
            'cache': cache,
            'g_free': g_free,
            'used': used,
            'active': active,
            'inactive': inactive,
            'available': available,
        }

if __name__ == '__main__':
    usage = sample_memory_usage()
    print(json.dumps(usage, indent=4))

下一步

订阅更新,获取更多学习资料,请关注我们的 微信公众号

../../../_images/wechat-mp-qrcode.png

小菜学编程