以/proc/meminfo为出发点:http://linuxperf.com/?p=142

内存大小

MemTotal

系统引导过程中,BIOS会保留部分内存,内核的【initrd】和由kernel code、data、init等数据会占用部分内存。引导完成后init code和init data释放。

MemTotal为系统引导完成后可供kernel支配的内存,在系统运行期间固定不变。

MemFree

尚未使用的内存

MemAvailable

估计值,MemFree+可回收部分(cache/bufferslab中的可回收部分)之和

Kernel内存分配

  1. alloc_pages/__get_free_page: 以页为单位分配;不会自动统计,只能观察到MemFree的减少,这部分内存的去向难以追踪,被称为内存黑洞
  2. vmalloc: 以字节为单位分配虚拟地址连续的内存块,可通过VmallocUsed统计使用情况。
  3. slab allocator;kmalloc: 以字节为单位分配物理地址连续的内存块,它是以slab为基础的,使用slab层的general caches — 大小为2^n,名称是kmalloc-32、kmalloc-64等,通过slab/SReclaimable/SUnreclaim精确统计。

内核

此处不含在引导阶段已经分配的内存(该部分内存也未计入MemTotal中)

内核占用内存=Slab+ VmallocUsed(/proc/vmallocinfo) + PageTables + KernelStack + HardwareCorrupted + Bounce + X(内存黑洞)

Slab

通过slab分配的内存Slab,分为可回收的部分SReclaimable和不可回收部分SUnreclaim

Vmalloc

VmallocUsed包含了vmalloc分配的物理内存和VM_IOREMAP、VM_MAP等操作的值。实际占用的内存通过/proc/vmallocinfo统计(byte)

grep vmalloc /proc/vmallocinfo | awk '{total+=$2}; END {print total}'

ps.疑问:我的设备上VmallocUsed为0,但/proc/vmallocinfo缺存在内存占用

内核模块的内存分配以page为单位,不足1page的分配1page;lsmod可查看已加载的内核模块,实际占用内存已在/proc/vmallocinfo中统计,无需重复计算

HardwareCorrupted

HardwareCorrupted为内存硬件故障时被删除的内存页

PageTables

PageTables统计用于翻译内存虚拟地址到物理地址的Page Table所占用的内存大小

ps. Page Frame(页帧)是在引导阶段已分配好的,不占用MemTotal

KernelStack

KernelStack统计内核栈消耗的内存。内存栈在内核态被内核调用,常驻内存。

Bounce

只能访问低端内存的老设备使用的bounce buffers占用的内存,用于缓存高端内存(如16M以上)

用户进程

用户进程占用内存:
围绕LRU进行统计
【(Active + Inactive + Unevictable) + (HugePages_Total * Hugepagesize)】

围绕Page Cache进行统计
当SwapCached为0的时候,用户进程的内存总计如下:
【(Cached + AnonPages + Buffers) + (HugePages_Total * Hugepagesize)】
当SwapCached不为0的时候,以上公式不成立,因为SwapCached可能会含有Shmem,而Shmem本来被含在Cached中,一旦swap-out就从Cached转移到了SwapCached,可是我们又不能把SwapCached加进上述公式中,因为SwapCached虽然不与Cached重叠却与AnonPages有重叠,它既可能含有Shared memory又可能含有Anonymous Pages。

围绕RSS/PSS进行统计
把/proc/[1-9]*/smaps 中的 Pss 累加起来就是所有用户进程占用的内存,但是还没有包括Page Cache中unmapped部分、以及HugePages,所以公式如下:
ΣPss + (Cached – mapped) + Buffers + (HugePages_Total * Hugepagesize)

Hugepages

区别于Transparent HugePages (THP),在/proc/meminfo独立统计。共3种使用方式

mount一个特殊的 hugetlbfs 文件系统,在上面创建文件,然后用mmap() 进行访问,如果要用 read() 访问也是可以的,但是 write() 不行。
通过shmget/shmat也可以使用Hugepages,调用shmget申请共享内存时要加上 SHM_HUGETLB 标志。
通过 mmap(),调用时指定MAP_HUGETLB 标志也可以使用Huagepages。

  • HugePages_Total对应vm.nr_hugepages,通过修改内核参数或/proc/sys/vm/nr_hugepages立即分配,不再属于MemFree
  • HugePages_Free表示尚未被使用的HugePages数量
  • HugePages_Rsvd表示已被申请(reserve)但尚未被使用的数量
  • HugePages_Surp表示超过系统设定的常驻HugePages数量(即vm.nr_hugepages),当程序执行init_hugepage_seg()时可能发生,HugePages_Surp=HugePages_Total-vm.nr_hugepages
  • Hugepagesize:HugePages内存页大小,Hugepagesize的修改需要操作系统支持,否则即使在内核参数中修改了default_hugepagesz也同样无效。

Hugepages占用的内存大小=HugePages_Total * Hugepagesize

AnonHugePages

统计的是Transparent HugePages,与/proc/meminfo的其他统计项有重叠,与进程的RSS/PSS是有重叠。在/proc/<pid>/smaps中可以查看单个进程的THP占用。

Huge pages (标准大页)和 Transparent Huge pages(透明大页)

默认情况下THP不用于shared memory和tmpfs,此时
【/proc/meminfo的AnonHugePages】==【所有进程的/proc//smaps中AnonHugePages之和】

LRU

页面回收算法(Page Frame Reclaiming)使用的数据结构。LRU lists中包含:

  1. LRU_INACTIVE_ANON – 对应 Inactive(anon)
  2. LRU_ACTIVE_ANON – 对应 Active(anon)
  3. LRU_INACTIVE_FILE – 对应 Inactive(file)
  4. LRU_ACTIVE_FILE – 对应 Active(file)
  5. LRU_UNEVICTABLE – 对应 Unevictable

Active代表最近被访问过的内存也;Inactive反之,由LRU算法根据是否优先回收判断;

file对应进程的代码、映射的文件等;anon代表进程的堆、栈等不与文件对应的匿名页;

file-backed pages在内存不足的时候可以直接写回对应的硬盘文件里,称为page-out,无需使用swap;

anonymous pages在内存不足时就只能写到硬盘上的交换区(swap)里,称为swap-out;

Unevictable代表不能pageout/swapout的内存页,包括VM_LOCKED的内存页、SHM_LOCK的共享内存页(又被统计在”Mlocked”中)、和ramfs。

Shmem

Shmem包括shared memory、tmpfs和devtmpfs

shared memory在内核中都是基于tmpfs,被视为文件系统,不算匿名页,不计入不被计,计入Cached和Mapped (当shmem被attached时候)。

由于它们背后并不存在真正的硬盘文件,所以在LRU中被放入Inactive(anon) 或 Active(anon)

AnonPages

AnonPages用于统计Anonymous pages(匿名页)的数量。

Anonymous Pages是与用户进程共存的,一旦进程退出,则Anonymous pages也释放。

Cached

Page Cache,所有file-backed pages

Mapped

Page Cache中与用户进程关联的部分

ps.疑问:Shmem与Mapped是什么关系

SwapCached

Shmem和AnonPages在被swap-out时短暂存放,被swap-in切页面内容还未发生改变(原来的swap空间也未被回收)

SwapCached中的匿名页如果需要被swap-out时,由于原先的swap空间依然存有该内容,无需进行swap操作。SwapCached不占用额外的内存

Mlocked

被mlock()系统调用锁定的内存,不会发生pageout/swapout,会从Active/Inactive LRU list移到Unevictable LRU list上

ps.疑问:为什么Mlocked与Unevictable不等同

Buffers

块设备(block device)所占用的缓存页。直接读写块设备(如硬盘)、以及文件系统元数据(metadata)比如SuperBlock所使用的缓存页。

参考附图

举例说明

MemTotal:        4013236 kB #kernel可支配的内存总数
MemFree:         2806400 kB #尚未使用的内存数
MemAvailable:    3458448 kB #可用内存(估计值)
Buffers:           83216 kB #块设备占用的缓存页
Cached:           723004 kB #Page cache,与普通文件对应的内存页
SwapCached:            0 kB #SwapCached的没错数量
Active:           543784 kB #LRU_ACTIVE
Inactive:         407816 kB #LRU_INACTIVE
Active(anon):     139780 kB #LRU_ACTIVE_ANON
Inactive(anon):      200 kB #LRU_INACTIVE_ANON
Active(file):     404004 kB #LRU_ACTIVE_FILE
Inactive(file):   407616 kB #LRU_INACTIVE_FILE
Unevictable:           0 kB #LRU_UNEVICTABLE
Mlocked:               0 kB #被mlock()锁定的内存
SwapTotal:       4015100 kB #swap大小
SwapFree:        4015100 kB #swap剩余空间
Dirty:               844 kB
Writeback:             0 kB #正准备回写硬盘的缓存页
AnonPages:        141932 kB #Anonymous pages占用的内存
Mapped:           202880 kB #正被用户进程关联的Cached
Shmem:              1528 kB #共享内存
Slab:             165580 kB #所有slab分配的内存(内核所用)
SReclaimable:      90228 kB #slab中可回收部分
SUnreclaim:        75352 kB #slab中不可回收部分
KernelStack:        5872 kB #kernel stack消耗的内存
PageTables:         5336 kB #Page Table占用内存大小
NFS_Unstable:          0 kB #发给NFS server但尚未写入硬盘的缓存页,包含在Slab中
Bounce:                0 kB #bounce buffers占用的内存
WritebackTmp:          0 kB
CommitLimit:     6021716 kB #允许超过的虚拟内存大小
Committed_AS:    1134352 kB
VmallocTotal:   34359738367 kB  #vmalloc可分配的内存大小
VmallocUsed:           0 kB #vmalloc分配的内存,除物理内存还统计了VM_IOREMAP、VM_MAP等操作的值
VmallocChunk:          0 kB #最大连续未被使用的vmalloc区域
HardwareCorrupted:     0 kB #应硬件问题删除的内存页
AnonHugePages:         0 kB #Transparent HugePages占用内存数
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0    #申请的HugePages总量
HugePages_Free:        0    #未被写入的HugePages数量
HugePages_Rsvd:        0    #已被申请(reserve)尚未使用的HugePages数量
HugePages_Surp:        0    #超过系统设定的常驻HugePages数量
Hugepagesize:       2048 kB #HugePages内存页大小
DirectMap4k:      167744 kB #TLB映射为4KB的内存数量
DirectMap2M:     4026368 kB #TLB映射为2MB的内存数量
DirectMap1G:     2097152 kB #TLB映射为1GB的内存数量

作者 Assaultcore

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注