Linux  内存详解,即top、free、vmstat、meminfo、Buffer和Cache的介绍 您所在的位置:网站首页 cache也是内存的一部分嘛为什么 Linux  内存详解,即top、free、vmstat、meminfo、Buffer和Cache的介绍

Linux  内存详解,即top、free、vmstat、meminfo、Buffer和Cache的介绍

2024-07-10 15:42| 来源: 网络整理| 查看: 265

温故而知新,可以为师矣。   1、top linux下的任务管理器       top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。top是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中CPU最“敏感”的任务列表.该命令可以按CPU使用.内存使用和执行时间对任务进行排序;而且该命令的很多特性都可以通过交互式命令或者在个人定制文件中进行设定。   $top     top - 09:14:56 up 264 days, 20:56,  1 user,  load average: 0.02, 0.04, 0.00     Tasks:  87 total,   1 running,  86 sleeping,   0 stopped,   0 zombie     Cpu(s):  0.0%us,  0.2%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.2%st     Mem:    377672k total,   322332k used,    55340k free,    32592k buffers     Swap:   397308k total,    67192k used,   330116k free,    71900k cached     PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND     1 root      20   0  2856  656  388 S  0.0  0.2   0:49.40 init     2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd     3 root      20   0     0    0    0 S  0.0  0.0   7:15.20 ksoftirqd/0     4 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 migration/0 第一行 09:14:56 : 系统当前时间 264 days, 20:56 : 系统开机到现在经过了多少时间 1 users : 当前2用户在线 load average: 0.02, 0.04, 0.00: 系统1分钟、5分钟、15分钟的CPU负载信息 第二行 Tasks:任务; 87 total:很好理解,就是当前有87个任务,也就是87个进程。 1 running:1个进程正在运行 86 sleeping:86个进程睡眠 0 stopped:停止的进程数 0 zombie:僵死的进程数 第三行 Cpu(s):表示这一行显示CPU总体信息 0.0%us:用户态进程占用CPU时间百分比,不包含renice值为负的任务占用的CPU的时间。 0.7%sy:内核占用CPU时间百分比 0.0%ni:改变过优先级的进程占用CPU的百分比 99.3%id:空闲CPU时间百分比 0.0%wa:等待I/O的CPU时间百分比 0.0%hi:CPU硬中断时间百分比 0.0%si:CPU软中断时间百分比 注:这里显示数据是所有cpu的平均值,如果想看每一个cpu的处理情况,按1即可;折叠,再次按1; 第四行 Men:内存的意思 8175320kk total:物理内存总量 8058868k used:使用的物理内存量 116452k free:空闲的物理内存量 283084k buffers:用作内核缓存的物理内存量 第五行 Swap:交换空间 6881272k total:交换区总量 4010444k used:使用的交换区量 2870828k free:空闲的交换区量 4336992k cached:缓冲交换区总量   进程信息 再下面就是进程信息: PID:进程的ID USER:进程所有者 PR:进程的优先级别,越小越优先被执行 NInice:值 VIRT:进程占用的虚拟内存 RES:  进程占用的物理内存 SHR:进程使用的共享内存 S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数 %CPU:进程占用CPU的使用率 %MEM:进程使用的物理内存和总内存的百分比 TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。 COMMAND:进程启动命令名称   top命令交互操作指令 下面列出一些常用的 top命令操作指令   q:退出top命令 :立即刷新 s:设置刷新时间间隔 c:显示命令完全模式 t::显示或隐藏进程和CPU状态信息 m:显示或隐藏内存状态信息 l:显示或隐藏uptime信息 f:增加或减少进程显示标志 S:累计模式,会把已完成或退出的子进程占用的CPU时间累计到父进程的MITE+ P:按%CPU使用率排行 T:按MITE+排行 M:按%MEM排行 e:  调整内存显示单位m/G u:指定显示用户进程 r:修改进程renice值 kkill:进程 i:只显示正在运行的进程 W:保存对top的设置到文件^/.toprc,下次启动将自动调用toprc文件的设置。 h:帮助命令。 q:退出   注:强调一下,使用频率最高的是P、T、M,因为通常使用top,我们就想看看是哪些进程最耗cpu资源、占用的内存最多; 注:通过”shift + >”或”shift + / proc / sys / vm / drop_caches 读一个大文件,并记录时间; 关闭该文件; 重读这个大文件,并记录时间; 第二次读应该比第一次快很多。原来我做过一个BerkeleyDB的读操作,大概要读5G的文件,几千万条记录。在我的环境上,第二次读比第一次大概可以快9倍左右。 free输出的第二行是从一个应用程序的角度看系统内存的使用情况。 对于FO[3][2],即-buffers/cache,表示一个应用程序认为系统被用掉多少内存; 对于FO[3][3],即+buffers/cache,表示一个应用程序认为系统还有多少内存; 因为被系统cache和buffer占用的内存可以被快速回收,所以通常FO[3][3]比FO[2][3]会大很多。    3.Buffer和Cache介绍 Cache(缓存),为了调高CPU和内存之间数据交换而设计,Buffer(缓冲)为了提高内存和硬盘(或其他I/O设备的数据交换而设计)。 Cache主要是针对读操作设计的 ,不过Cache概念可能容易混淆,我理解为CPU本身就有Cache,包括一级缓存、二级缓存、三级缓存,我们知道CPU所有的指令操作对接的都是内存,而CPU的处理能力远高于内存速度,所以为了不让CPU资源闲置,Intel等公司在CPU内部集成了一些Cache,但毕竟不能放太多电路在里面,所以这部分Cache并不是很大,主要是用来存放一些常用的指令和常用数据, 真正大部分Cache的数据应该是占用内存的空间来缓存请求过的数据,即上面的Cached部分 (这部分纯属个人理解,正确与否有待考证)。 Buffer主要是针对写操作设计的 ,更细的说是针对内存和硬盘之间的写操作来设计的,目的是将写的操作集中起来进行,减少磁盘碎片和硬盘反复寻址过程,提高性能。在Linux系统内部有一个守护进程会定期清空Buffer中的内容,将其写入硬盘内,当手动执行sync命令时也会触发上述操作。    3.1. 常见症状 症状一:在Linux中频繁存取文件,物理内存很快用光,而cached一直在增长。 解释:Linux会对每次请求过的数据缓存在cache里,好处就是CPU的处理速度远远高于内存,所以在CPU和内存通讯的时候可以快速从cache中命中结果返回。 症状二:Swap被占用。 解释: 内存可能不够了,才会占Swap ,所以Swap可以作为服务器监控的一项指标,引起注意。    3.2. 手动清理Swap和buffers/cache (1) 清理Swap      swapoff -a && swapon -a     操作说明:如果已经使用了Swap,且当前清空下+buffers/cache还有空间,在执行swapoff -a操作时,会触发把Swap中的内容交换到内存中,数据不会丢失。 (2) 清理buffers/cache:     sync; sync; sync;&& echo 3 >/proc/sys/vm/drop_caches     sleep 2     echo 0 > /proc/sys/vm/drop_caches     操作说明:     sync-->将缓存的内从写回到硬盘中;     echo 3 >/proc/sys/vm/drop_caches-->修改drop_caches的值为3, 默认为0,改为3系统会清理缓存的内容 ;     sleep 2 --> 等一下,防止上一步没执行完;     echo 0 >/proc/sys/vm/drop_caches --> 改回默认值    设置的值分别为1、2、3。它们所表示的含义为: echo 1 > /proc/sys/vm/drop_caches :表示清除pagecache。 echo 2 > /proc/sys/vm/drop_caches:表示清除回收slab分配器中的对象(包括目录项缓存和inode缓存)。slab分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的pagecache。 echo 3 > /proc/sys/vm/drop_caches:表示清除pagecache和slab分配器中的缓存对象。   4. 虚拟内存统计vmstat   vmstat [-V] [-n] [delay [count]] -V表示打印出版本信息; -n表示在周期性循环输出时,输出的头部信息仅显示一次; delay是两次输出之间的延迟时间; count是指按照这个时间间隔统计的次数。 /root$vmstat 5 5 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 6 0 0 27900472 204216 28188356 0 0 0 9 1 2 11 14 75 0 0 9 0 0 27900380 204228 28188360 0 0 0 13 33312 126221 22 20 58 0 0 2 0 0 27900340 204240 28188364 0 0 0 10 32755 125566 22 20 58 0 0 如果是因为缺少内存,系统响应变慢很明显,因为这使得系统不停的做换入换出的工作; 进一步的监视内存使用情况,可使用vmstat工具,实时动态监视操作系统的内存和虚拟内存的动态变化。 参考:  vmstat 监视内存使用情况  ;   5. /proc/meminfo /proc/meminfo是了解Linux系统内存使用状况的主要接口,我们最常用的”free”、”vmstat”等命令就是通过它获取数据的 ,/proc/meminfo所包含的信息比”free”等命令要丰富得多,然而真正理解它并不容易。     比如我们知道”Cached”统计的是文件缓存页,manpage上说是“In-memory  cache  for  files read from the disk (the page cache)”,那为什么它不等于[Active(file)+Inactive(file)]? AnonHugePages与AnonPages、HugePages_Total有什么联系和区别? 很多细节在手册中并没有讲清楚,本文对此做了一点探究。   负责输出 /proc/meminfo的源代码是: fs/proc/meminfo.c : meminfo_proc_show() 详解: MemTotal: 所有内存(RAM)大小,减去一些预留空间和内核的大小。 MemFree: 完全没有用到的物理内存,lowFree+highFree MemAvailable: 在不使用交换空间的情况下,启动一个新的应用最大可用内存的大小,计算方式:MemFree+Active(file)+Inactive(file)-(watermark+min(watermark,Active(file)+Inactive(file)/2)) Buffers: 块设备所占用的缓存页,包括:直接读写块设备以及文件系统元数据(metadata),比如superblock使用的缓存页。 Cached: 表示普通文件数据所占用的缓存页。 SwapCached: swap cache中包含的是被确定要swapping换页,但是尚未写入物理交换区的匿名内存页。那些匿名内存页,比如用户进程malloc申请的内存页是没有关联任何文件的,如果发生swapping换页,这类内存会被写入到交换区。 Active: active包含active anon和active file Inactive: inactive包含inactive anon和inactive file Active(anon): anonymous pages(匿名页),用户进程的内存页分为两种:与文件关联的内存页(比如程序文件,数据文件对应的内存页)和与内存无关的内存页(比如进程的堆栈,用malloc申请的内存),前者称为file pages或mapped pages,后者称为匿名页。 Inactive(anon): 见上 Active(file): 见上 Inactive(file): 见上 SwapTotal: 可用的swap空间的总的大小(swap分区在物理内存不够的情况下,把硬盘空间的一部分释放出来,以供当前程序使用) SwapFree: 当前剩余的swap的大小 Dirty: 需要写入磁盘的内存去的大小 Writeback: 正在被写回的内存区的大小 AnonPages: 未映射页的内存的大小 Mapped: 设备和文件等映射的大小 Slab: 内核数据结构slab的大小 SReclaimable: 可回收的slab的大小 SUnreclaim: 不可回收的slab的大小 PageTables: 管理内存页页面的大小 NFS_Unstable: 不稳定页表的大小 VmallocTotal: Vmalloc内存区的大小 VmallocUsed: 已用Vmalloc内存区的大小 VmallocChunk: vmalloc区可用的连续最大快的大小  

MemTotal

系统从加电开始到引导完成, f irmware/BIOS要保留一些内存,kernel本身要占用一些内存,最后剩下可供kernel支配的内存就是MemTotal 。这个值在系统运行期间一般是固定不变的。可参阅 解读DMESG中的内存初始化信息 。

MemFree

表示系统尚未使用的内存。[MemTotal-MemFree]就是已被用掉的内存。

MemAvailable

有些应用程序会根据系统的可用内存大小自动调整内存申请的多少,所以需要一个记录当前可用内存数量的统计值,MemFree并不适用,因为MemFree不能代表全部可用的内存, 系统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收,所以这部分可回收的内存加上MemFree才是系统可用的内存,即MemAvailable 。 /proc/meminfo中的 MemAvailable是内核使用特定的算法估算出来的,要注意这是一个估计值,并不精确 。

内存黑洞

追踪Linux系统的内存使用一直是个难题,很多人试着把能想到的各种内存消耗都加在一起,kernel text、kernel modules、buffer、cache、slab、page table、process RSS…等等,却总是与物理内存的大小对不上,这是为什么呢? 因为Linux kernel并没有滴水不漏地统计所有的内存分配, kernel动态分配的内存中就有一部分 没有计入/proc/meminfo中 。 我们知道,Kernel的动态内存分配通过以下几种接口: alloc_pages/__get_free_page: 以页为单位分配 vmalloc: 以字节为单位分配虚拟地址连续的内存块 slab allocator kmalloc: 以字节为单位分配物理地址连续的内存块,它是以slab为基础的,使用slab层的general caches — 大小为2^n,名称是kmalloc-32、kmalloc-64等(在老kernel上的名称是size-32、size-64等)。   (1)通过slab层分配的内存会被精确统计,可以参见/proc/meminfo中的slab/SReclaimable/SUnreclaim; (2)通过vmalloc分配的内存也有统计,参见/proc/meminfo中的VmallocUsed 和 /proc/vmallocinfo(下节中还有详述); (3)而 通过 alloc_pages 分配的内存不会自动统计,除非调用 alloc_pages的内核模块或驱动程序 主动进行统计 ,否则我们只能看到free memory减少了,但从/proc/meminfo中看不出它们具体用到哪里去了。比如在VMware guest上有一个常见问题,就是VMWare ESX宿主机会通过guest上的Balloon driver(vmware_balloon module)占用guest的内存,有时占用得太多会导致guest无内存可用,这时去检查guest的/proc/meminfo只看见MemFree很少、但看不出内存的去向,原因就是Balloon driver通过alloc_pages分配内存,没有在/proc/meminfo中留下统计值,所以很难追踪。 6. 内存都到哪里去了? 使用内存的,不是kernel就是用户进程,下面我们就分类讨论。 注:page cache比较特殊,很难区分是属于kernel还是属于进程,其中被进程mmap的页面自然是属于进程的了,而 另一些页面没有被mapped到任何进程,那就只能算是属于kernel了 。 6.1. 内核 内核所用内存的静态部分,比如内核代码、页描述符等数据在引导阶段就分配掉了,并不计入MemTotal里,而是算作Reserved(在dmesg中能看到)。而内核所用内存的动态部分,是通过上文提到的几个接口申请的,其中通过alloc_pages申请的内存有可能未纳入统计,就像黑洞一样。 下面讨论的都是/proc/meminfo中所统计的部分。 6.1.1 SLAB 通过slab分配的内存被统计在以下三个值中: SReclaimable: slab中可回收的部分。调用kmem_getpages()时加上SLAB_RECLAIM_ACCOUNT标记,表明是可回收的,计入SReclaimable,否则计入SUnreclaim。 SUnreclaim: slab中不可回收的部分。 Slab: slab中所有的内存,等于以上两者之和。 6.1.2 VmallocUsed 通过vmalloc分配的内存都统计在/proc/meminfo的 VmallocUsed 值中,但是要注意这个值不止包括了分配的物理内存,还统计了VM_IOREMAP、VM_MAP等操作的值,譬如VM_IOREMAP是把IO地址映射到内核空间、并未消耗物理内存,所以我们要把它们排除在外。 从物理内存分配的角度,我们只关心VM_ALLOC操作,这可以从/proc/vmallocinfo中的vmalloc记录看到: # grep vmalloc /proc/vmallocinfo . . . 0xffffc90004702000 - 0xffffc9000470b000    36864  alloc_large_system_hash + 0x171 / 0x239  pages = 8  vmalloc  N0 = 8 0xffffc9000470b000 - 0xffffc90004710000    20480  agp_add_bridge + 0x2aa / 0x440  pages = 4  vmalloc  N0 = 4 0xffffc90004710000 - 0xffffc90004731000   135168  raw_init + 0x41 / 0x141  pages = 32  vmalloc  N0 = 32 0xffffc90004736000 - 0xffffc9000473f000    36864  drm_ht_create + 0x55 / 0x80  [ drm ]  pages = 8  vmalloc  N0 = 8 0xffffc90004744000 - 0xffffc90004746000     8192  dm_table_create + 0x9e / 0x130  [ dm_mod ]  pages = 1  vmalloc  N0 = 1 0xffffc90004746000 - 0xffffc90004748000     8192  dm_table_create + 0x9e / 0x130  [ dm_mod ]  pages = 1  vmalloc  N0 = 1 . . . 注:/proc/vmallocinfo中能看到vmalloc来自哪个调用者(caller),那是vmalloc()记录下来的,相应的源代码可见: mm/vmalloc.c: vmalloc > __vmalloc_node_flags > __vmalloc_node > __vmalloc_node_range > __get_vm_area_node > setup_vmalloc_vm 通过vmalloc分配了多少内存,可以统计/proc/vmallocinfo中的vmalloc记录,例如: # grep vmalloc /proc/vmallocinfo | awk '{total+=$2}; END {print total}' 23375872 一些driver以及网络模块和文件系统模块可能会调用vmalloc,加载内核模块(kernel module)时也会用到,可参见 kernel/module.c。 6.1.3 kernel modules (内核模块) 系统已经加载的内核模块可以用 lsmod 命令查看,注意第二列就是内核模块所占内存的大小,通过它可以统计内核模块所占用的内存大小,但这并不准,因为”lsmod”列出的是[init_size+core_size],而实际给kernel module分配的内存是以page为单位的,不足 1 page的部分也会得到整个page,此外每个module还会分到一页额外的guard page。下文我们还会细说。 # lsmod | less Module                   Size   Used  by rpcsec_gss _krb5         31477   0 auth _rpcgss             59343   1  rpcsec_gss_krb5 nfsv4                  474429   0 dns _resolver            13140   1  nfsv4 nfs                    246411   1  nfsv4 lockd                   93977   1  nfs sunrpc                 295293   5  nfs , rpcsec_gss_krb5 , auth_rpcgss , lockd , nfsv4 fscache                 57813   2  nfs , nfsv4 . . . lsmod的信息来自/proc/modules,它显示的size包括init_size和core_size,相应的源代码参见: // kernel/module.c static  int  m_show ( struct  seq_file  * m ,  void  * p ) { . . .          seq_printf ( m ,  "%s %u" ,                     mod -> name ,  mod -> init_size  +  mod -> core_size ) ; . . . } 注:我们可以在 /sys/module// 目录下分别看到coresize和initsize的值。 kernel module的内存是通过vmalloc()分配的(参见下列源代码),所以在/proc/vmallocinfo中会有记录,也就是说我们可以不必通过”lsmod”命令来统计kernel module所占的内存大小,通过/proc/vmallocinfo就行了,而且还比lsmod更准确,为什么这么说呢? // kernel/module.c static  int  move_module ( struct  module  * mod ,  struct  load_info  * info ) { . . .          ptr  =  module_alloc_update_bounds ( mod -> core_size ) ; . . .          if  ( mod -> init_size )  {                  ptr  =  module_alloc_update_bounds ( mod -> init_size ) ; . . . }   // 注:module_alloc_update_bounds()最终会调用vmalloc_exec() 因为给kernel module分配内存是以page为单位的,不足 1 page的部分也会得到整个page,此外,每个module还会分到一页额外的guard page。 详见:mm/vmalloc.c: __get_vm_area_node() 而”lsmod”列出的是[init_size+core_size],比实际分配给kernel module的内存小。我们做个实验来说明: # 先卸载floppy模块 $  modprobe  - r  floppy # 确认floppy模块已经不在了 $  lsmod  |  grep  floppy # 记录vmallocinfo以供随后比较 $  cat  / proc / vmallocinfo  >  vmallocinfo . 1   # 加载floppy模块 $  modprobe  - a  floppy # 注意floppy模块的大小是69417字节: $  lsmod  |  grep  floppy floppy                  69417   0 $  cat  / proc / vmallocinfo  >  vmallocinfo . 2 # 然而,我们看到vmallocinfo中记录的是分配了73728字节: $  diff  vmallocinfo . 1  vmallocinfo . 2 68a69 >  0xffffffffa03d7000 - 0xffffffffa03e9000    73728  module_alloc_update_bounds + 0x14 / 0x70  pages = 17  vmalloc  N0 = 17   # 为什么lsmod看到的内存大小与vmallocinfo不同呢? # 因为给kernel module分配内存是以page为单位的,而且外加一个guard page # 我们来验证一下: $  bc  - q 69417 % 4096 3881     . . .          cached  =  global_page_state ( NR_FILE_PAGES )  -                          total_swapcache_pages ( )  -  i . bufferram ; . . . } “SwapCached”内存同时也在LRU中,还在”AnonPages”或”Shmem”中,它本身并不占用额外的内存。 6.2.9 Mlocked “Mlocked”统计的是被mlock()系统调用锁定的内存大小。被锁定的内存因为不能pageout/swapout,会从Active/Inactive LRU list移到Unevictable LRU list上。也就是说,当”Mlocked”增加时,”Unevictable”也同步增加,而”Active”或”Inactive”同时减小;当”Mlocked”减小的时候,”Unevictable”也同步减小,而”Active”或”Inactive”同时增加。 “Mlocked”并不是独立的内存空间,它与以下统计项重叠:LRU Unevictable,AnonPages,Shmem,Mapped等。 6.2.10 Buffers “Buffers”表示块设备(block device)所占用的缓存页,包括:直接读写块设备、以及文件系统元数据(metadata)比如SuperBlock所使用的缓存页。它与“Cached”的区别在于,”Cached”表示普通文件所占用的缓存页。参见我的另一篇文章 http://linuxperf.com/?p=32 “Buffers”所占的内存同时也在LRU list中,被统计在Active(file)或Inactive(file)。

 

注:通过阅读源代码可知,块设备的读写操作涉及的缓存被纳入了LRU,以读操作为例,do_generic_file_read()函数通过 mapping->a_ops->readpage() 调用块设备底层的函数,并调用 add_to_page_cache_lru() 把缓存页加入到LRU list中。参见: filemap.c: do_generic_file_read > add_to_page_cache_lru 7. 其它问题

DirectMap

/proc/meminfo中的DirectMap所统计的不是关于内存的使用,而是一个反映TLB效率的指标。TLB(Translation Lookaside Buffer)是位于CPU上的缓存,用于将内存的虚拟地址翻译成物理地址,由于TLB的大小有限,不能缓存的地址就需要访问内存里的page table来进行翻译,速度慢很多。为了尽可能地将地址放进TLB缓存,新的CPU硬件支持比4k更大的页面从而达到减少地址数量的目的, 比如2MB,4MB,甚至1GB的内存页,视不同的硬件而定。”DirectMap4k”表示映射为4kB的内存数量, “DirectMap2M”表示映射为2MB的内存数量,以此类推。所以DirectMap其实是一个反映TLB效率的指标。

Dirty pages到底有多少?

/proc/meminfo 中有一个Dirty统计值,但是它未能包括系统中全部的dirty pages,应该再加上另外两项:NFS_Unstable 和 Writeback,NFS_Unstable是发给NFS server但尚未写入硬盘的缓存页,Writeback是正准备回写硬盘的缓存页。即: 系统中全部dirty pages = ( Dirty + NFS_Unstable + Writeback ) 注1:NFS_Unstable的内存被包含在Slab中,因为nfs request内存是调用kmem_cache_zalloc()申请的。

 

注2:anonymous pages不属于dirty pages。 参见mm/vmscan.c: page_check_dirty_writeback() “Anonymous pages are not handled by flushers and must be written from reclaim context.”

为什么【Active(anon)+Inactive(anon)】不等于AnonPages?

因为Shmem(即Shared memory & tmpfs) 被计入LRU Active/Inactive(anon),但未计入 AnonPages。所以一个更合理的等式是: 【Active(anon)+Inactive(anon)】 = 【AnonPages + Shmem】 但是这个等式在某些情况下也不一定成立,因为: 如果shmem或anonymous pages被mlock的话,就不在Active(non)或Inactive(anon)里了,而是到了Unevictable里,以上等式就不平衡了; 当anonymous pages准备被swap-out时,分几个步骤:先被加进swap cache,再离开AnonPages,然后离开LRU Inactive(anon),最后从swap cache中删除,这几个步骤之间会有间隔,而且有可能离开AnonPages就因某些情况而结束了,所以在某些时刻以上等式会不平衡。 【注:参见mm/vmscan.c: shrink_page_list(): 它调用的add_to_swap()会把swap cache页面标记成dirty,然后调用try_to_unmap()将页面对应的page table mapping都删除,再调用pageout()回写dirty page,最后try_to_free_swap()把该页从swap cache中删除。】

为什么【Active(file)+Inactive(file)】不等于Mapped?

因为LRU Active(file)和Inactive(file)中不仅包含mapped页面,还包含unmapped页面; Mapped中包含”Shmem”(即shared memory & tmpfs),这部分内存被计入了LRU Active(anon)或Inactive(anon)、而不在Active(file)和Inactive(file)中。

为什么【Active(file)+Inactive(file)】不等于 Cached?

因为”Shmem”(即shared memory & tmpfs)包含在Cached中,而不在Active(file)和Inactive(file)中; Active(file)和Inactive(file)还包含Buffers。 如果不考虑mlock的话,一个更符合逻辑的等式是: 【Active(file) + Inactive(file) + Shmem】== 【Cached + Buffers】 如果有mlock的话,等式应该如下(mlock包括file和anon两部分,/proc/meminfo中并未分开统计,下面的mlock_file只是用来表意,实际并没有这个统计值): 【Active(file) + Inactive(file) + Shmem +  mlock_file】== 【Cached + Buffers】

 

注: 测试的结果以上等式通常都成立,但内存发生交换的时候以上等式有时不平衡,我猜可能是因为有些属于Shmem的内存swap-out的过程中离开Cached进入了Swapcached,但没有立即从swap cache删除、仍算在Shmem中的缘故。 8. Linux的内存都用到哪里去了? 尽管不可能精确统计Linux系统的内存,但大体了解还是可以的。

kernel内存的统计方式应该比较明确,即

【Slab+  VmallocUsed   + PageTables + KernelStack + HardwareCorrupted + Bounce + X】 注1:VmallocUsed其实不是我们感兴趣的,因为它还包括了VM_IOREMAP等并未消耗物理内存的IO地址映射空间,我们只关心VM_ALLOC操作,(参见1.2节),所以实际上应该统计/proc/vmallocinfo中的vmalloc记录,例如(此处单位是byte): # grep vmalloc /proc/vmallocinfo | awk '{total+=$2}; END {print total}' 23375872 注2:kernel module的内存被包含在VmallocUsed中,见1.3节。 注3:X表示直接通过alloc_pages/__get_free_page分配的内存,没有在/proc/meminfo中统计,不知道有多少,就像个黑洞。

用户进程的内存主要有三种统计口径:

围绕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)

所以系统内存的使用情况可以用以下公式表示:

MemTotal = MemFree +【Slab+ VmallocUsed + PageTables + KernelStack + HardwareCorrupted + Bounce + X】+【Active + Inactive + Unevictable + (HugePages_Total * Hugepagesize)】 MemTotal = MemFree +【Slab+ VmallocUsed + PageTables + KernelStack + HardwareCorrupted + Bounce + X】+【Cached + AnonPages + Buffers + (HugePages_Total * Hugepagesize)】 MemTotal = MemFree +【Slab+ VmallocUsed + PageTables + KernelStack + HardwareCorrupted + Bounce + X】+【ΣPss + (Cached – mapped) + Buffers + (HugePages_Total * Hugepagesize)】    


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有