以/proc/meminfo为出发点:http://linuxperf.com/?p=142
内存大小
MemTotal
系统引导过程中,BIOS会保留部分内存,内核的【initrd】和由kernel code、data、init等数据会占用部分内存。引导完成后init code和init data释放。
MemTotal为系统引导完成后可供kernel支配的内存,在系统运行期间固定不变。
MemFree
尚未使用的内存
MemAvailable
估计值,MemFree+可回收部分(cache/buffer
、slab
中的可回收部分)之和
Kernel内存分配
- alloc_pages/__get_free_page: 以页为单位分配;不会自动统计,只能观察到MemFree的减少,这部分内存的去向难以追踪,被称为内存黑洞
- vmalloc: 以字节为单位分配虚拟地址连续的内存块,可通过VmallocUsed统计使用情况。
- 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占用。
默认情况下THP不用于shared memory和tmpfs,此时
【/proc/meminfo的AnonHugePages】==【所有进程的/proc/
LRU
页面回收算法(Page Frame Reclaiming)使用的数据结构。LRU lists中包含:
- LRU_INACTIVE_ANON – 对应 Inactive(anon)
- LRU_ACTIVE_ANON – 对应 Active(anon)
- LRU_INACTIVE_FILE – 对应 Inactive(file)
- LRU_ACTIVE_FILE – 对应 Active(file)
- 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的内存数量