内存管理中的overcommit
1. 什么是overcommit
Linux calls this overcommit, which refers to the fact that thekernel allows a process to allocate more memory than is currently available.The kernel is effectively speculating that the memory will be available whenneeded.
Linux对大部分申请内存的请求都回复"yes",以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存。这种技术叫做Overcommit。当linux发现内存不足时,会发生OOM killer(OOM=out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存。
当oom-killer发生时,linux会选择杀死哪些进程?选择进程的函数是oom_badness函数(在mm/oom_kill.c中),该函数会计算每个进程的点数(0~1000)。点数越高,这个进程越有可能被杀死。每个进程的点数跟oom_score_adj有关,而且oom_score_adj可以被设置(-1000最低,1000最高)。
2. Linux configure the overcommit
The Linux kernel supports the following overcommit handling modes
0 - Heuristic overcommithandling. Obvious overcommits of address space are refused. Used for a typicalsystem. It ensures a seriously wild allocation fails while allowing overcommitto reduce swap usage. root is allowed toallocate slighly more memory in this mode. This is the default. (表示检查是否有足够的内存可用,如果是,允许分配;如果内存不够,拒绝该请求,并返回一个错误给应用程序。)
1 - Alwaysovercommit. Appropriate for some scientific applications. (表示根据vm.overcommit_ratio定义的值,允许分配超出一定内存(物理内存加上交换内存)的请求。vm.overcommit_ratio参数是一个百分比,加上内存量决定内存可以超量分配多少内存。例如,vm.overcommit_ratio值为50,而内存有1GB,那么这意味着在内存分配请求失败前,加上交换内存,内存将允许高达1.5GB的内存分配请求。)
2 - Don'tovercommit. The total address space commit for the system is not permitted toexceed swap + a configurable percentage (default is 50) of physical RAM. Dependingon the percentage you use, in most situations this means a process will not bekilled while accessing pages but will receive errors on memory allocation as appropriate.(内核允许分配超过所有物理内存和交换空间总和的内存.)
Theovercommit policy is set via the sysctl `vm.overcommit_memory'.
The overcommit percentage is set via `vm.overcommit_ratio'.
Linux内存管理smap
在Linux内核 2.6.16中引入了一个系统内存接口特性,这个接口位于/proc/$pid/目录下的smaps文件中,一看内容发现是进程内存映像信息,比同一目录下的maps文件更详细些。
400df000-4048c000 r--s 00000000 1f:05286 /data/dalvik-cache/system@framework@core.jar@classes.dex
Size: 3764 kB
Rss: 1804 kB
Pss: 1804 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 1804 kB
Private_Dirty: 0 kB
Referenced: 1804 kB
Anonymous: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
以上述输出结果为例:
400df000-4048c000 r--s 00000000 1f:05 286/data/dalvik-cache/system@framework@core.jar@classes.dex
Ø 400df000-4048c000: 是该虚拟内存段的开始和结束位置;
Ø r--s: 内存段的权限,最后一位p代表私有,s代表共享;
Ø 0000000: 该虚拟内存段在对应的映射文件中的偏移量;
Ø 1f:05: 文件的主设备和次设备号;
Ø 286: 被映射到虚拟内存的文件的索引节点号;
Ø /data/dalvik-cache/system@framework@core.jar@classes.dex: 被映射到虚拟内存的文件名称。后面带(deleted)的是内存数据,可以被销毁;
Ø Size: 是进程使用内存空间,并不一定实际分配了内存(VSS);
Ø Rss: 是实际分配的内存(不需要缺页中断就可以使用的);
Ø Pss: 是平摊计算后的使用内存(有些内存会和其他进程共享,例如mmap进来的);
Ø Shared_Clean: 和其他进程共享的未改写页面;
Ø Shared_Dirty: 和其他进程共享的已改写页面;
Ø Private_Clean: 未改写的私有页面页面;
Ø Private_Dirty: 已改写的私有页面页面;
Ø Referenced: 标记为访问和使用的内存大小;
Ø Anonymous: 不来自于文件的内存大小;
Ø Swap: 存在于交换分区的数据大小(如果物理内存有限,可能存在一部分在主存一部分在交换分区);
Ø KernelPageSize: 内核页大小;
Ø MMUPageSize: MMU页大小,基本和Kernel页大小相同;
其中Dirty页面如果没有交换机制的情况下,应该是不能回收的。
精确分析内存占用可以用Private内存信息来衡量。
Linux内存管理proc status
Develop>cat /proc/24475/status
Name: netio 可执行程序的名字
State: R (running) 进程状态
Tgid: 24475 线程组号
Pid: 24475 进程id
PPid: 19635 父进程id
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256 该进程最大文件描述符个数
Groups: 0
VmPeak: 6330708 kB 内存使用峰值
VmSize: 268876 kB 进程虚拟地址空间大小
VmLck: 0 kB 进程锁住的物理内存大小,锁住的物理内存无法交换到硬盘
VmHWM: 16656 kB
VmRSS: 11420 kB 进程正在使用的物理内存大小
VmData: 230844 kB 进程数据段大小
VmStk: 136 kB 进程用户态栈大小
VmExe: 760 kB 进程代码段大小
VmLib: 7772 kB 进程使用的库映射到虚拟内存空间的大小
VmPTE: 120 kB 进程页表大小
VmSwap: 0 kB
Threads: 5
SigQ: 0/63346
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000001000000
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: ffffffffffffffff
CapEff: ffffffffffffffff
CapBnd: ffffffffffffffff
Cpus_allowed: 01
Cpus_allowed_list: 0
Mems_allowed: 01
Mems_allowed_list: 0
voluntary_ctxt_switches: 201
nonvoluntary_ctxt_switches: 909
Linux内存管理proc meminfo
Develop>cat /proc/meminfo
MemTotal: 8112280 kB 所有可用RAM大小 (即物理内存减去一些预留位和内核的二进制代码大小)
MemFree: 4188636 kB LowFree与HighFree的总和,被系统留着未使用的内存
Buffers: 34728 kB 用来给文件做缓冲大小
Cached: 289740 kB 被高速缓冲存储器(cache memory)用的内存的大小 (等于 diskcache minus SwapCache )
SwapCached: 0 kB 被高速缓冲存储器(cache memory)用的交换空间的大小已经被交换出来的内存,但仍然被存放在swapfile中。用来在需要的时候很快的被替换而不需要再次打开I/O端口
Active: 435240 kB 在活跃使用中的缓冲或高速缓冲存储器页面文件的大小,除非非常必要否则不会被移作他用
Inactive: 231512 kB 在不经常使用中的缓冲或高速缓冲存储器页面文件的大小,可能被用于其他途径.
Active(anon): 361252 kB
Inactive(anon): 120688 kB
Active(file): 73988 kB
Inactive(file): 110824 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB 交换空间的总大小
SwapFree: 0 kB 未被使用交换空间的大小
Dirty: 0 kB 等待被写回到磁盘的内存大小
Writeback: 0 kB 正在被写回到磁盘的内存大小
AnonPages: 348408 kB 未映射页的内存大小
Mapped: 33600 kB 已经被设备和文件等映射的大小
Shmem: 133536 kB
Slab: 55984 kB 内核数据结构缓存的大小,可以减少申请和释放内存带来的消耗
SReclaimable: 25028 kB 可收回Slab的大小
SUnreclaim: 30956 kB 不可收回Slab的大小(SUnreclaim+SReclaimable=Slab)
KernelStack: 1896 kB 内核栈区大小
PageTables: 8156 kB 管理内存分页页面的索引表的大小
NFS_Unstable: 0 kB 不稳定页表的大小
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2483276 kB
Committed_AS: 1804104 kB
VmallocTotal: 34359738367 kB 可以vmalloc虚拟内存大小
VmallocUsed: 565680 kB 已经被使用的虚拟内存大小
VmallocChunk: 34359162876 kB
HardwareCorrupted: 0 kB
HugePages_Total: 1536 大页面数目
HugePages_Free: 0 空闲大页面数目
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB 大页面一页大小
DirectMap4k: 10240 kB
DirectMap2M: 8302592 kB
VSS/RSS/PSS/USS