linux的内存映射(二)

我们先来看幅图:
在这里插入图片描述
Linux内存管理的最底层是buddy内存管理方案,即伙伴算法,管理伙伴算法我们不做详诉,有兴趣的可以自行学习,我们这里只要知道buddy内存池中只能分配2^n个page的内存,比如1,2,4,8……个pages,然而正常使用的时候不会碰巧就需要1,2,4,8……个pages。所以基于buddy内存池,还需要有上一级的内存管理系统,内核里面采用的是slab,slub,slob;而用户空间也有自己的内存管理方案,比如基于glibc的malloc/free内存管理方案。
关于glibc的malloc内存管理方案本文先不做详诉,我们大概了解以下几点,以便对本文的话题有个更加宏观的认识:
如果glibc的内存池中没有内存了,那么malloc就会通过mmap或者brk向buddy申请内存。
free调用不会立即将内存还给buddy,而是会还给glibc的内存池。
如果glibc的内存池中还有足够的内存,那么malloc直接从glibc内存池中分配内存,不会像buddy申请内存。
关于mmap的行为总结下来就是一下几点:

  • mmap的时候只会创建一个vma,此vma也有可能跟之前的vma合并成一个vma,并不会真正的分配物理内存。
  • 当读mmap出来的内存的时候,会发生缺页异常,并将读所涉及到内存都映射到同一个物理页,称为zero page,zero page只有读权限,没有写权限。
  • 当写mmap出来的内存的时候,会在此发生缺页异常,并将所涉及到的内存映射到真实的物理页,并且这些物理页有写权限。
    本文的目的就是从行为以及代码两个方面来印证以上描述。
    mmap代码验证如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

#define MMAP_SIZE 0x4000
int main(char *argv[], int argc)
{
        int i;
        int tmp;
        void *addr;
        char *p;
        pid_t process_id;
        process_id = getpid();
        printf("pid is %d\n", process_id);
        printf("before mmap\n");
        getchar();
        addr = mmap(NULL, MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
                  -1, 0);
        printf("after mmap\n");
        getchar();
        p = (char *)addr;
        for(i=0; i< MMAP_SIZE;i++)
                tmp = p[i];

        printf("after read\n");
        getchar();

        for(i=0; i<MMAP_SIZE; i++)
                p[i] = 0x1;

        printf("after write\n");
        getchar();

        return 0;
}

mmap之前的page fault中断以及内存分配情况
执行test程序,打印出before mmap后,通过pidof 找到测试程序的pid为13070,并获取获得如下关键信息:

virtual-machine:~/work$ ps -o maj_flt -o min_flt -p 13070
 MAJFL  MINFL
     0     77
virtual-machine:~/work$ pmap 13070
13070:   ./test
0000000000400000      4K r-x-- test
0000000000600000      4K r---- test
0000000000601000      4K rw--- test
0000000001d10000    132K rw---   [ anon ]
00007f2f56000000   1792K r-x-- libc-2.23.so
00007f2f561c0000   2048K ----- libc-2.23.so
00007f2f563c0000     16K r---- libc-2.23.so
00007f2f563c4000      8K rw--- libc-2.23.so
00007f2f563c6000     16K rw---   [ anon ]
00007f2f563ca000    152K r-x-- ld-2.23.so
00007f2f565d0000     12K rw---   [ anon ]
00007f2f565ef000      4K r---- ld-2.23.so
00007f2f565f0000      4K rw--- ld-2.23.so
00007f2f565f1000      4K rw---   [ anon ]
00007ffc66eab000    132K rw---   [ stack ]
00007ffc66f66000     12K r----   [ anon ]
00007ffc66f69000      8K r-x--   [ anon ]
ffffffffff600000      4K r-x--   [ anon ]
 total             4356K

缺页异常数量是77,所有的vma内存分配如上。前的十六进制数字表示分配该段虚拟内存的起始地址。

after mmap之后搜集信息如下:

virtual-machine:~/work$ ps -o maj_flt -o min_flt -p 13070
 MAJFL  MINFL
     0     77

virtual-machine:~/work$ pmap 13070
13070:   ./test
0000000000400000      4K r-x-- test
0000000000600000      4K r---- test
0000000000601000      4K rw--- test
0000000001d10000    132K rw---   [ anon ]
00007f2f56000000   1792K r-x-- libc-2.23.so
00007f2f561c0000   2048K ----- libc-2.23.so
00007f2f563c0000     16K r---- libc-2.23.so
00007f2f563c4000      8K rw--- libc-2.23.so
00007f2f563c6000     16K rw---   [ anon ]
00007f2f563ca000    152K r-x-- ld-2.23.so
00007f2f565d0000     12K rw---   [ anon ]
00007f2f565eb000     16K rw---   [ anon ]
00007f2f565ef000      4K r---- ld-2.23.so
00007f2f565f0000      4K rw--- ld-2.23.so
00007f2f565f1000      4K rw---   [ anon ]
00007ffc66eab000    132K rw---   [ stack ]
00007ffc66f66000     12K r----   [ anon ]
00007ffc66f69000      8K r-x--   [ anon ]
ffffffffff600000      4K r-x--   [ anon ]
 total             4372K

我们看到page fault没有增加,但是vma增加了一个:

00007f2f565eb000     16K rw---   [ anon ]

那么哪里可以找到实际分配的物理内存的大小呢?可以通过
pmap -x查看,RSS这里是0;方法二,也可以通过可以通过查看/proc/13070/smaps文件来确认

Address           Kbytes     RSS   Dirty Mode  Mapping
...
00007f2f565eb000      16       0       0 rw---   [ anon ]
...
---------------- ------- ------- -------
total kB            4372    1328      80

after read之后信息搜集如下:

virtual-machine:~/work$ ps -o maj_flt -o min_flt -p 13070
 MAJFL  MINFL
     0     81

wqq@wqq-virtual-machine:~/work$ pmap 13070
13070:   ./test
0000000000400000      4K r-x-- test
0000000000600000      4K r---- test
0000000000601000      4K rw--- test
0000000001d10000    132K rw---   [ anon ]
00007f2f56000000   1792K r-x-- libc-2.23.so
00007f2f561c0000   2048K ----- libc-2.23.so
00007f2f563c0000     16K r---- libc-2.23.so
00007f2f563c4000      8K rw--- libc-2.23.so
00007f2f563c6000     16K rw---   [ anon ]
00007f2f563ca000    152K r-x-- ld-2.23.so
00007f2f565d0000     12K rw---   [ anon ]
00007f2f565eb000     16K rw---   [ anon ]
00007f2f565ef000      4K r---- ld-2.23.so
00007f2f565f0000      4K rw--- ld-2.23.so
00007f2f565f1000      4K rw---   [ anon ]
00007ffc66eab000    132K rw---   [ stack ]
00007ffc66f66000     12K r----   [ anon ]
00007ffc66f69000      8K r-x--   [ anon ]
ffffffffff600000      4K r-x--   [ anon ]
 total             4372K

缺页异常增加了四个,因为有4个page被读了嘛!然而Rss没有增加,说明根本没有分配实际的物理内存,完全符合预期。

after write之后信息搜集如下:

virtual-machine:~/work$ ps -o maj_flt -o min_flt -p 13070
 MAJFL  MINFL
     0     85
virtual-machine:~/work$ pmap -x 13070
13070:   ./test
Address           Kbytes     RSS   Dirty Mode  Mapping
...
00007f2f565eb000      16      16      16 rw---   [ anon ]
...
---------------- ------- ------- -------
total kB            4372    1344      96

新增了四个page fault,并且RSS是16K,此时才真正的分配了物理内存。
通过查看/proc/13070/smaps也发现如下:

7f2f565eb000-7f2f565ef000 rw-p 00000000 00:00 0
Size:                 16 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:                  16 kB
Pss:                  16 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:        16 kB
Referenced:           16 kB
Anonymous:            16 kB
LazyFree:              0 kB
AnonHugePages:         0 kB
ShmemPmdMapped:        0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
Locked:                0 kB
ProtectionKey:         0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值