linux中申请内存的情况分析( 二 )


PID USERPRNIVIRTRESSHR S%CPU%MEMTIME+ COMMAND12375 miao2002764852788 S0.00.00:00.00 a.outVIRT即虚拟内存大小,RES即实际内存大小,这两个一般最重要,就够了 。如果按照每个VMA计算,求和,可以通过/proc/pid/smaps文件去计算,这个文件比maps的文件更详细,值得仔细分析,计算验证下:
cat /proc/12375/smaps|grep Size|grep -v Page|awk -F: '{print $2}'|awk '{sum += $1}; END {print sum}'2764虚拟内存对的上,实际内存计算:
# cat /proc/12375/smaps|grep Rss|grep -v Page|awk -F: '{print $2}'|awk '{sum += $1}; END {print sum}'1388这个和实际内存对不上,按照Pss(即共享内存做了平分处理后,仍然有差距),差距原因是应用申请内存通过c的库申请的,库申请的时候也会多申请一些,还有一些对齐之类的,有些差异可能也正常 。
还有个比较简单的计算程序内存的方法:
oot@ubuntu-lab:/home/miao/c-test/mm-test# cat /proc/24546/statusName:a.outUmask:0002State:S (sleeping)Tgid:24546Ngid:0Pid:24546PPid:5359TracerPid:0Uid:1000100010001000Gid:1000100010001000FDSize: 256Groups: 4 24 27 30 46 110 1000 NStgid: 24546NSpid:24546NSpgid: 24546NSsid:5359VmPeak:1051332 kBVmSize:1051332 kBVmLck:0 kBVmPin:0 kBVmHWM:1049776 kBVmRSS:1049776 kBRssAnon:1048672 kBRssFile:1104 kBRssShmem:0 kB....VmRSS 这个即是程序占用的内存,一般情况下VmRSS = RssAnon+RssFile+RssShmem
四 系统内存分析其实我们遇到系统的性能问题,如果怀疑是内存问题,那么很有可能用free命令看下,然后top命令看看,top下对程序的占用内存情况进行排序,找到可疑进程,然后再做上面的进程占用内存情况的分析 。(整个系统所占内存包括内核占的内存和应用程序所占内存两个部分) 。
其实最该看的两个内核导出文件:/proc/meminfo和 /proc/vmstat 前者是内存的占用分类情况,而后者是内存分配,规整、脏页回写等更细节的内存数据的动态变化,通过这些变化发现问题,由于后者不是重点,重点来看下前者,在我机器上统计如下:
miao@ubuntu-lab:~$ cat /proc/meminfo MemTotal:4926744 kB//所有可用的内存大小,物理内存减去预留位和内核使用 。系统从加电开始到引导完成,firmware/BIOS要预留一些内存,内核本身要占用一些内存,最后剩下可供内核支配的内存就是MemTotal 。这个值在系统运行期间一般是固定不变的,重启会改变 。MemFree:3663620 kB//表示系统尚未使用的内存 。MemAvailable:4209668 kB //真正的系统可用内存,系统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收,所以这部分可回收的内存加上MemFree才是系统可用的内存Buffers:78416 kB//用来给块设备做缓存的内存,(文件系统的 metadata、pages)Cached:661976 kB//分配给文件缓冲区的内存,例如vi一个文件,就会将未保存的内容写到该缓冲区SwapCached:0 kB//被swap到磁盘上的匿名内存,又一次被拉入内存统计Active:325864 kB//经常使用的高速缓冲存储器页面文件大小Inactive:618264 kB//不经常使用的高速缓冲存储器文件大小Active(anon):4564 kB//活跃的匿名内存Inactive(anon):215464 kB//不活跃的匿名内存Active(file):321300 kB//活跃的文件使用内存Inactive(file):402800 kB//不活跃的文件使用内存Unevictable:19372 kB//不能被释放的内存页Mlocked:19372 kB//系统调用 mlock 家族允许程序在物理内存上锁住它的部分或全部地址空间 。这将阻止Linux 将这个内存页调度到交换空间(swap space),即使该程序已有一段时间没有访问这段空间SwapTotal:4194300 kB //交换空间总内存SwapFree:4194300 kB//交换空间空闲内存Dirty:148 kB//等待被写回到磁盘的脏内存Writeback:0 kB//正在被写回的脏内存AnonPages:223144 kB//未映射页的内存/映射到用户空间的非文件页表大小MApped:210380 kB//映射文件内存Shmem:13168 kB//已经被分配的共享内存,所有tmpfs类型的文件系统占用的空间都计入共享内存KReclaimable:60332 kB Slab:137076 kB//内核数据结构缓存SReclaimable:60332 kB//可收回slab内存SUnreclaim:76744 kB//不可收回slab内存KernelStack:7568 kB// 每一个用户线程都会分配一个kernel stack(内核栈),内核栈虽然属于线程,但用户态的代码不能访问,只有通过系统调用(syscall)、自陷(trap)或异常(exception)进入内核态的时候才会用到,也就是说内核栈是给kernel code使用的 。在x86系统上Linux的内核栈大小是固定的8K或16KPageTables:5876 kB//管理内存分页的索引表(物理内存和虚拟内存映射表)的大小 NFS_Unstable:0 kB // The amount, in kibibytes, of NFS pages sent to the server but not yet committed to the stable storage.Bounce:0 kB // 有些老设备只能访问低端内存,比如16M以下的内存,当应用程序发出一个I/O 请求,DMA的目的地址却是高端内存时(比如在16M以上),内核将在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处 。这种额外的数据拷贝被称为“bounce buffering”,会降低I/O 性能 。大量分配的bounce buffers 也会占用额外的内存 。WritebackTmp:0 kB// USE用于临时写回缓冲区的内存CommitLimit:6657672 kB// 系统实际可分配内存总量Committed_AS:1742228 kB// 当前已分配的内存总量VmallocTotal:34359738367 kB // 虚拟内存空间能分配的总内存大小VmallocUsed:57524 kB// 虚拟内存空间使用的内存大小VmallocChunk:0 kB// 虚拟内存空间可分配的最大的逻辑连续的内存大小Percpu:89600 kBHardwareCorrupted:0 kBAnonHugePages:0 kB //AnonHugePages统计的是Transparent HugePages (THP),THP与Hugepages不是一回事,与进程的RSS/PSS是有重叠的,如果用户进程用到了THP,进程的RSS/PSS也会相应增加ShmemHugePages:0 kBShmemPmdMapped:0 kBFileHugePages:0 kBFilePmdMapped:0 kBHugePages_Total:0//超级大页总大小如果进程使用了Hugepages,它的RSS/PSS不会增加 。HugePages_Free:0//超级大页空闲大小HugePages_Rsvd:0 // 超级大页剩余内存HugePages_Surp:0 // 剩余超级大页数量Hugepagesize:2048 kB//超级大页 尺寸为2MBHugetlb:0 kBDirectMap4k:198464 kB //DirectMap所统计的不是关于内存的使用,而是一个反映TLB效率的指标 表示映射为4kB的内存数量 TLB(Translation Lookaside Buffer)是位于CPU上的缓存,用于将内存的虚拟地址翻译成物理地址,由于TLB的大小有限,不能缓存的地址就需要访问内存里的page table来进行翻译,速度慢很多 。DirectMap2M:3913728 kB // 表示映射为2MB的内存数量DirectMap1G:1048576 kB // 表示映射为1GB的内存数量


推荐阅读