Linux 下面查看内存有多种渠道,好比经过命令 ps ,top,free 等,好比经过/proc系统,通常须要比较详细和精确地知道整机内存/某个进程内存的使用状况,最好经过/proc 系统,下面介绍/proc系统下内存相关的几个文件html
转自:http://blog.chinaunix.net/uid-20769366-id-1849119.htmlnode
几乎看什么内核漏洞分析之类的文章,第一眼都是被 cat /proc/{pid}/maps 产生的一堆奇怪的信息唬住了,都不敢往下看 竟然没有搜到关于它们的详细介绍,旁边也没有表头什么的解释信息 那就我来整理一下吧,方便后人。 ls /proc 能看到一些数字命名的文件夹,这个就很少说了,什么pid、fd的知识仍是容易弄到的 拿init开刀, [root@localhost proc]# cat /proc/1/statm 487 185 133 31 0 67 0 很简单地返回7组数字,每个的单位都是一页 (常见的是4KB) 分别是 size:任务虚拟地址空间大小 Resident:正在使用的物理内存大小 Shared:共享页数 Trs:程序所拥有的可执行虚拟内存大小 Lrs:被映像倒任务的虚拟内存空间的库的大小 Drs:程序数据段和用户态的栈的大小 dt:脏页数量 接下来看看maps [root@localhost proc]# cat /proc/1/maps 00110000-00111000 r-xp 00110000 00:00 0 [vdso] 0032b000-00347000 r-xp 00000000 fd:00 852733 /lib/ld-2.8.so 00347000-00348000 r--p 0001c000 fd:00 852733 /lib/ld-2.8.so 00348000-00349000 rw-p 0001d000 fd:00 852733 /lib/ld-2.8.so 0034b000-004ae000 r-xp 00000000 fd:00 852734 /lib/libc-2.8.so 004ae000-004b0000 r--p 00163000 fd:00 852734 /lib/libc-2.8.so 004b0000-004b1000 rw-p 00165000 fd:00 852734 /lib/libc-2.8.so 004b1000-004b4000 rw-p 004b1000 00:00 0 08048000-08067000 r-xp 00000000 fd:00 843075 /sbin/init 08067000-08068000 rw-p 0001e000 fd:00 843075 /sbin/init 08b42000-08b6a000 rw-p 08b42000 00:00 0 [heap] b8046000-b8048000 rw-p b8046000 00:00 0 bfb4e000-bfb63000 rw-p bffeb000 00:00 0 [stack] 第一列表明内存段的虚拟地址 第二列表明执行权限,r,w,x没必要说,p=私有 s=共享。不用说,heap和stack段不该该有x,不然就容易被xx,不过这个跟具体的版本有关 第三列表明在进程地址里的偏移量 第四列映射文件的主设备号和次设备号,经过 cat /proc/devices,得知fd是253 device-mapper 第五列映像文件的节点号,即inode 第六列是映像文件的路径 之前我很奇怪怎么会有两个相同的文件路径,原来 08048000-08067000 r-xp 00000000 fd:00 843075 /sbin/init 08067000-08068000 rw-p 0001e000 fd:00 843075 /sbin/init 一个是只读的,是代码段,一个是读写的,是数据段 至于为何共享库分红了三个 0034b000-004ae000 r-xp 00000000 fd:00 852734 /lib/libc-2.8.so 004ae000-004b0000 r--p 00163000 fd:00 852734 /lib/libc-2.8.so 004b0000-004b1000 rw-p 00165000 fd:00 852734 /lib/libc-2.8.so 其中的004ae000-004b0000 r--p 00163000 fd:00 852734 /lib/libc-2.8.so 仍是不能理解
单个进程的内存查看 cat /proc/[pid] 下面有几个文件: maps , smaps, statuslinux
maps 文件能够查看某个进程的代码段、栈区、堆区、动态库、内核区对应的虚拟地址,若是你还不了解linux进程的内存空间,能够参考这里。android
下图是maps文件内存示例缓存
Develop>cat /proc/self/maps 00400000-0040b000 r-xp 00000000 fd:00 48 /mnt/cf/orig/root/bin/cat 0060a000-0060b000 r--p 0000a000 fd:00 48 /mnt/cf/orig/root/bin/cat 0060b000-0060c000 rw-p 0000b000 fd:00 48 /mnt/cf/orig/root/bin/cat 代码段 0060c000-0062d000 rw-p 00000000 00:00 0 [heap] 堆区 7f1fff43b000-7f1fff5d4000 r-xp 00000000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so 7f1fff5d4000-7f1fff7d3000 ---p 00199000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so 7f1fff7d3000-7f1fff7d7000 r--p 00198000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so 7f1fff7d7000-7f1fff7d9000 rw-p 0019c000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so 7f1fff7d9000-7f1fff7dd000 rw-p 00000000 00:00 0 7f1fff7dd000-7f1fff7fe000 r-xp 00000000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so 7f1fff9f9000-7f1fff9fd000 rw-p 00000000 00:00 0 7f1fff9fd000-7f1fff9fe000 r--p 00020000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so 7f1fff9fe000-7f1fff9ff000 rw-p 00021000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so 7f1fff9ff000-7f1fffa00000 rw-p 00000000 00:00 0 7fff443de000-7fff443ff000 rw-p 00000000 00:00 0 [stack] 用户态栈区 7fff443ff000-7fff44400000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 内核区
有时候能够经过不断查看某个进程的maps文件,经过查看其虚拟内存(堆区)是否不停增加来简单判断进程是否发生了内存溢出。数据结构
maps文件只能显示简单的分区,smap文件能够显示每一个分区的更详细的内存占用数据app
下图是smaps文件内存示例, 实际显示内容会将每个区都显示出来,下面我只拷贝了代码段和堆区,ide
每个区显示的内容项目是同样的,smaps文件各项含义能够参考这里ui
Develop>cat /proc/self/smaps 00400000-0040b000 r-xp 00000000 fd:00 48 /mnt/cf/orig/root/bin/cat Size: 44 kB 虚拟内存大小 Rss: 28 kB 实际使用物理内存大小 Pss: 28 kB Shared_Clean: 0 kB 页面被改,则是dirty,不然是clean,页面引用计数>1,是shared,不然是private Shared_Dirty: 0 kB Private_Clean: 28 kB Private_Dirty: 0 kB Referenced: 28 kB Anonymous: 0 kB AnonHugePages: 0 kB Swap: 0 kB 处于交换区的页面大小 KernelPageSize: 4 kB 操做系统一个页面大小 MMUPageSize: 4 kB 体系结构MMU一个页面大小 Locked: 0 kB
0060c000-0062d000 rw-p 00000000 00:00 0 [heap]
Size: 132 kB
Rss: 8 kB
Pss: 8 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8 kB
Referenced: 8 kB
Anonymous: 8 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kBidea
下图是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下内存占用是一个比较复杂的概念,不能
简单经过一个单一指标就判断某个程序“内存消耗”大小,缘由有下面2点:
关于内存的使用分析及本文几个命令的说明也能够参考这里
下面是查看整机内存使用状况的文件 /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
手动解析HPROF 文件的过程。
maps 23258 b5758000-b5e3d000 r-xp 00000000 fd:00 223303 /data/data/com.xxx.phone/files/storage/com.xxx.maindex/version.1/lib/libxxx.so //代码段 23259 b5e3d000-b5e3e000 ---p 00000000 00:00 0 23260 b5e3e000-b5e7a000 r--p 006e5000 fd:00 223303 /data/data/com.xxx.phone/files/storage/com.xxx.maindex/version.1/lib/libxxx.so 23261 b5e7a000-b5e86000 rw-p 00721000 fd:00 223303 //数据段 && userstack /data/data/com.xxx.phone/files/storage/com.xxx.maindex/version.1/lib/libxxx.so b5758000-b5e3d000 r-xp 00000000 fd:00 223303//地址范围b5758000-b5e3d000 权限读,写-可执行,私有 (代码段) 进程内偏移量00000000 主设备号fd (253 device-mapper)次设备号00, inode 223303 hprof 中一个内存分配的item: z 1 sz 1382400 num 1 bt f3a9da84 f5ad0d00 b58edda4 b58b90d4 b58baf40 b58bc9a0 b58bd120 b57f9ebc b57fa490 b57a23f8 f6f17702 f6ef1040 //address2line b58edda4−b5758000 = 195DA4 $NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-addne -e out/target/product/generic/symbols/system/lib/libxxx-3.5.2.2.so 195DA4 /home/lyl/source/frameworks/main/osal/src/opengl/hal_video_opengl.cpp:184
23264 b6069000-b606a000 ---p 00000000 00:00 0 23265 b606a000-b606b000 ---p 00000000 00:00 0 23266 b606b000-b616e000 rw-p 00000000 00:00 0 [stack:23688] 23267 b616e000-b616f000 ---p 00000000 00:00 0 23268 b616f000-b6170000 ---p 00000000 00:00 0 23269 b6170000-b6273000 rw-p 00000000 00:00 0 [stack:23687] 能够看出每一个栈帧空间以前8K 保护区。//TODO