全部博文(573)
分类: LINUX
2015-12-09 14:46:18
#cat maps
00008000-00009000 r-xp 00000000 1f:12 288 /mnt/msc_int0/hello (1)
00010000-00011000 rw-p 00000000 1f:12 288 /mnt/msc_int0/hello (1)
00011000-00032000 rwxp 00011000 00:00 0[heap] (33)
40000000-40002000 rw-p 40000000 00:00 0 (2)
41000000-41017000 r-xp 00000000 1f:0d 817360 /lib/ld-2.3.3.so (23)
4101e000-41020000 rw-p 00016000 1f:0d 817360 /lib/ld-2.3.3.so (2)
41028000-41120000 r-xp 00000000 1f:0d 817593 /lib/libc-2.3.3.so (248)
41120000-41128000 ---p 000f8000 1f:0d 817593 /lib/libc-2.3.3.so (8)
41128000-41129000 r--p 000f8000 1f:0d 817593 /lib/libc-2.3.3.so (1)
41129000-4112c000 rw-p 000f9000 1f:0d 817593 /lib/libc-2.3.3.so (3)
4112c000-4112e000 rw-p 4112c000 00:00 0 (2)
befeb000-bf000000 rwxp befeb000 00:00 0[stack] (21)
上面每个虚拟内存区域所占大小见上面最右侧一列,单位页。
第一列:虚拟内存段的起始和结束地址,表示物理内存中可执行文件或库的各段映射到虚拟内存中的某一段空间,或者
进程堆栈段的虚拟内存空间。
第二列:代表该段虚拟内存段的权限,r=可读,w=可写,x=可执行,s=共享,p=私有。
第三列:虚拟内存区域在被映射文件中的偏移,该偏移量是页(4KB)对齐,偏移为0的表示ELF文件的该段只占用一页。
第四列:存储被映射文件存储体的主次设备号。
第五列:被映射文件的inode号。
第六列:被映射文件的路径。
上面文件涉及的都是虚拟内存的概念,所以可以看出这个进程占用了多少虚拟内存,不过最重要的是需要知道该进程
吃掉了多少物理内存,下面这个文件可以得到使用的物理内存。
#cat memmap
2
1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1
4949494949494949491649494949494949494949494949
1 1
4917171717111617171717171717174949 0 049 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 49 0 0 0(+46)
0 0 0 0 0 0 0 044 042424242 0 0 0 0 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 47 0 0 0 0 0 0 0(+42)
04747484949494949494949 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 049 0 0 0 0 0 0 0 0(+49)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 04849 0 0 0 04849 0 0 047 049 0 0 0 0 0 0 0 0 0 0 04949 0(+ 50)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 046 0 0 0 0 0 0 0 0 0 0 0 0 0 0(+50)
44 0 0 0 0 0 0 0 0 0 0(+11)
0 0 0 0 0 0 0 0
49
1 1 1
1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
这个文件需要和maps文件对照起来看,memmap每一行对应maps文件的一行。
以下解读规则为猜测,并无从源码角度验证(十进制的数在linux中不会加入前导0,也就是000 = 0,01 = 1,012 = 12):
1. 只要出现了0,那么该0就代表一个虚拟内存页框,系统并未为其分配物理内存页;
2. 如果有数值出现,那么如何判断到底几个数字代表一个虚拟页框呢?这个就需要从maps文件中计算出每一段虚拟
内存空间的大小,然后一个一个来数咯。
这个数值不仅表示了系统已为该页框分配了物理页,同时也代表了该虚拟页框映射的物理页有多少个进程在使用。
例如:
00008000-00009000 r-xp 00000000 1f:12 288 /mnt/msc_int0/hello (1)
<<< >>>
2
这里看出系统为hello的text段映射了一个物理页,而且是使用一个数字表示一个虚拟页框,同时也看到有2个进程
引用了该物理页。
00011000-00032000 rwxp 00011000 00:00 0[heap] (33)
<<< >>>
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
这是hello进程的堆段,这个堆虚拟空间分配了132KB,但是实际上只分配了4KB的物理内存,也可以证实堆地址是
向上增长的。
41000000-41017000 r-xp 00000000 1f:0d 817360 /lib/ld-2.3.3.so (23)
<<< >>>
4949494949494949491649494949494949494949494949
这是ld进程的txt段,系统为其23个虚拟页框全部分配了物理页,而且是2位数字表示一个虚拟页框,同时可以看到
每个物理页都有49个进程在引用。
befeb000-bf000000 rwxp befeb000 00:00 0[stack] (21)
<<< >>>
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
这是hello的stack段,系统开辟了21个虚拟页框,但实际上只做了2个物理页的映射。也能够证实stack的地址是向下生长的。
对于上面数字最长的那一行,表示的是进程/lib/libc-2.3.3.so的虚拟空间,共248个虚拟页框,有数值的是2位代表一个页框,仔细数一数的话,可以证实。
ld和libc共享库占用的内存也反映到我们的这个程序上,导致表象上看起来我这小程序貌似是吃了不少内存,
所以除了进程自己的代码段,数据段,堆段,stack段之外的共享库占用的内存都是不真实的。由于代码段这种系统共享的特性,导致了我们想了解一个进程使用了多少内存,给我一个数,这样一个简单的要求,变得很复杂。
不过在2.6.16的linux版本中/proc/{pid}中出现了smaps的文件,这个可读性比较好。
# cat smaps
...
08048000-08107000 r-xp 00000000 08:01 392453 /bin/bash
Size: 764 kB
Rss: 592 kB
Pss: 296 kB
Shared_Clean: 592 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 592 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
...
08108000-0810d000 rw-p 000bf000 08:01 392453 /bin/bash
Size: 20 kB
Rss: 20 kB
Pss: 20 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 20 kB
Referenced: 20 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
...
0964e000-0967c000 rw-p 00000000 00:00 0 [heap]
Size: 184 kB
Rss: 184 kB
Pss: 184 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 184 kB
Referenced: 184 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
...
bfe07000-bfe28000 rw-p 00000000 00:00 0 [stack]
Size: 136 kB
Rss: 28 kB
Pss: 28 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 28 kB
Referenced: 28 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
size: 是进程使用内存空间,并不一定实际分配了物理内存;
Rss: "Resident Set Size",实际驻留"在内存中"的内存数. 不包括已经交换出去的页面。RSS还包括了与其它
进程共享的内存区域,通常用于共享库;
Pss: Private Rss, Rss中私有的内存页面;
Shared_Clean: Rss中和其他进程共享的未改写页面;
Shared_Dirty: Rss和其他进程共享的已改写页面;
Private_Clean: Rss中改写的私有页面页面;
Private_Dirty: Rss中已改写的私有页面页面;
(其中Dirty页面如果没有交换机制的情况下,应该是不能回收的)
网上流传着Ben Maurer写的一个perl脚本可以将一个进程的使用情况整理得更清楚:
#!/usr/bin/perl
# Copyright Ben Maurer
# you can distribute this under the MIT/X11 License
use Linux::Smaps;
my $pid=shift @ARGV;
unless ($pid) {
print "./smem.pl
exit 1;
}
my $map=Linux::Smaps->new($pid);
my @VMAs = $map->vmas;
format STDOUT =
VMSIZE: @######## kb
$map->size
RSS: @######## kb total
$map->rss
@######## kb shared
$map->shared_clean + $map->shared_dirty
@######## kb private clean
$map->private_clean
@######## kb private dirty
$map->private_dirty
.
write;
printPrivateMappings ();
printSharedMappings ();
sub sharedMappings () {
return grep { ($_->shared_clean + $_->shared_dirty) > 0 } @VMAs;
}
sub privateMappings () {
return grep { ($_->private_clean + $_->private_dirty) > 0 } @VMAs;
}
sub printPrivateMappings ()
{
$TYPE = "PRIVATE MAPPINGS";
$^ = 'SECTION_HEADER';
$~ = 'SECTION_ITEM';
$- = 0;
$= = 100000000;
foreach $vma (sort {-($a->private_dirty <=> $b->private_dirty)}
privateMappings ()) {
$size = $vma->size;
$dirty = $vma->private_dirty;
$clean = $vma->private_clean;
$file = $vma->file_name;
write;
}
}
sub printSharedMappings ()
{
$TYPE = "SHARED MAPPINGS";
$^ = 'SECTION_HEADER';
$~ = 'SECTION_ITEM';
$- = 0;
$= = 100000000;
foreach $vma (sort {-(($a->shared_clean + $a->shared_dirty)
<=>
($b->shared_clean + $b->shared_dirty))}
sharedMappings ()) {
$size = $vma->size;
$dirty = $vma->shared_dirty;
$clean = $vma->shared_clean;
$file = $vma->file_name;
write;
}
}
format SECTION_HEADER =
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$TYPE
@>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
"vmsize" "rss clean" "rss dirty" "file"
.
format SECTION_ITEM =
@####### kb @####### kb @####### kb @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$size $clean $dirty $file
.
使用之前需要先安装Linux::Smaps模块:
perl -MCPAN -e 'install Linux::Smaps' // 需要网络
#./seme.pl 1762
VMSIZE: 6812 kb
RSS: 1876 kb total
1496 kb shared
24 kb private clean
356 kb private dirty
PRIVATE MAPPINGS
vmsize rss clean rss dirty file
184 kb 0 kb 184 kb [heap]
136 kb 0 kb 28 kb [stack]
20 kb 0 kb 20 kb /bin/bash
20 kb 0 kb 20 kb
12 kb 0 kb 12 kb
8 kb 0 kb 8 kb /lib/libc-2.12.1.so
8 kb 0 kb 8 kb /lib/libncurses.so.5.7
8 kb 0 kb 8 kb
8 kb 0 kb 8 kb
4 kb 0 kb 4 kb /lib/libc-2.12.1.so
4 kb 0 kb 4 kb /lib/libncurses.so.5.7
4 kb 0 kb 4 kb /lib/libdl-2.12.1.so
4 kb 0 kb 4 kb /lib/libdl-2.12.1.so
4 kb 0 kb 4 kb /lib/ld-2.12.1.so
4 kb 0 kb 4 kb /lib/ld-2.12.1.so
4 kb 0 kb 4 kb /lib/libnss_nis-2.12.1.so
4 kb 0 kb 4 kb /lib/libnss_nis-2.12.1.so
4 kb 0 kb 4 kb /lib/libnss_files-2.12.1.so
4 kb 0 kb 4 kb /lib/libnss_files-2.12.1.so
4 kb 0 kb 4 kb /lib/libnss_compat-2.12.1.so
4 kb 0 kb 4 kb /lib/libnss_compat-2.12.1.so
4 kb 0 kb 4 kb /lib/libnsl-2.12.1.so
4 kb 0 kb 4 kb /lib/libnsl-2.12.1.so
4 kb 0 kb 4 kb /bin/bash
764 kb 24 kb 0 kb /bin/bash
SHARED MAPPINGS
vmsize rss clean rss dirty file
764 kb 600 kb 0 kb /bin/bash
1372 kb 528 kb 0 kb /lib/libc-2.12.1.so
216 kb 108 kb 0 kb /lib/libncurses.so.5.7
112 kb 104 kb 0 kb /lib/ld-2.12.1.so
1612 kb 48 kb 0 kb /usr/lib/locale/locale-archive
76 kb 20 kb 0 kb /lib/libnsl-2.12.1.so
28 kb 20 kb 0 kb /usr/lib/gconv/gconv-modules.cache
36 kb 16 kb 0 kb /lib/libnss_nis-2.12.1.so
24 kb 16 kb 0 kb /lib/libnss_compat-2.12.1.so
40 kb 12 kb 0 kb /lib/libnss_files-2.12.1.so
2048 kb 12 kb 0 kb /usr/lib/locale/locale-archive
8 kb 8 kb 0 kb /lib/libdl-2.12.1.so
4 kb 4 kb 0 kb [vdso]
从上面看到rss大小被分成了两个部分: private(私有)和shared(共享).
private rss就是我们最关心的进程实际占用的内存数.
参考文档:
1.
2. http://netcome.iteye.com/blog/746931
3. http://challengezcy.blog.163.com/blog/static/692292722009112395221795/
4. http://blog.csdn.net/tinnycloud/archive/2010/04/30/5546440.aspx