Linux内核虚拟内存管理之匿名映射缺页异常分析( 四 )


下面用图说话:

Linux内核虚拟内存管理之匿名映射缺页异常分析

文章插图
 
3.4 读之后写匿名页读之后写匿名页,其实已经很简单了,那就是发生COW写时复制缺页 。下面依然看图说话:
Linux内核虚拟内存管理之匿名映射缺页异常分析

文章插图
 
四,应用层实验实验1:主要体验下内核的按需分配页策略!实验代码:mmap映射10 * 4096 * 4096/1M=160M内存空间,映射和写页前后获得内存使用情况:
1 #include <stdio.h>2 #include <stdlib.h>3 #include <sys/mman.h>4 #include <unistd.h>567 #define MAP_LEN (10 * 4096 * 4096)89 int main(int argc, char **argv)10 {11char *p;12int i;131415puts("before mmap ->please exec: free -mn");16sleep(10);17p = (char *)mmap(0, MAP_LEN, PROT_READ |PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);1819puts("after mmap ->please exec: free -mn");20puts("before write....n");21sleep(10);2223for(i=0;i <4096 *10; i++)24p[4096 * i] = 0x55;252627puts("after write ->please exec: free -mn");2829pause();3031return 0;32 }执行结果:
出现“before mmap ->please exec: free -m”打印后执行:
$ free -m总计已用空闲共享缓冲/缓存可用内存:15921656146279688978214交换:1629070215588出现“after mmap ->please exec: free -m”打印后执行:
$ free -m总计已用空闲共享缓冲/缓存可用内存:15921656548377188728236交换:1629070215588出现“after write ->please exec: free -m”后执行:
$:~/study/user_test/page-fault$ free -m总计已用空闲共享缓冲/缓存可用内存:15921672732277088718076交换:1629070215588我们只关注已用内存,可以发现映射前后基本上已用内存没有变化(考虑到其他内存申请情况存在,也会有内存变化)是6561M和6565M,说明mmap的时候并没有分配物理内存,写之后发现内存使用为6727M, 6727-6565=162M与我们mmap的大小基本一致,说明了匿名页实际写的时候才会分配等量的物理内存 。
 
实验2:主要体验下匿名页读之后写内存页申请情况 实验代码:mmap映射10 * 4096 * 4096/1M=160M内存空间,映射、读然后写页前后获得内存使用情况:
1 #include <stdio.h>2 #include <stdlib.h>3 #include <sys/mman.h>4 #include <unistd.h>567 #define MAP_LEN (10 * 4096 * 4096)89 int main(int argc, char **argv)10 {11char *p;12int i;131415puts("before mmap...pls show free:.n");16sleep(10);?17p = (char *)mmap(0, MAP_LEN, PROT_READ |PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);1819puts("after mmap....n");2021puts("before read...pls show free:.n");22sleep(10);2324puts("start read....n");252627for(i=0;i <4096 *10; i++)28printf("%d ", p[4096 * i]);29printf("n");3031puts("after read....pls show free:n");3233sleep(10);3435puts("start write....n");3637for(i=0;i <4096 *10; i++)38p[4096 * i] = 0x55;394041puts("after write...pls show free:.n");4243pause();4445return 0;46 }执行结果:出现"before mmap ->please exec: free -m" 后执行:
$ free -m总计已用空闲共享缓冲/缓存可用内存:15921659063178087008164交换:1629070215588出现"before read ->please exec: free -m"后执行:
$ free -m总计已用空闲共享缓冲/缓存可用内存:15921658664477086908178交换:1629070215588出现"after read ->please exec: free -m"后执行:
$ free -m总计已用空闲共享缓冲/缓存可用内存:15921658762478987098158交换:1629070215588出现"after write ->please exec: free -m"后执行:
$ free -m总计已用空闲共享缓冲/缓存可用内存:15921674946278987097996交换:1629070215588可以发现:读之后和之前基本上内存使用没有变化(实际上映射到了0页,这是内核初始化时候分配好的),知道写之后6749-6587=162M符合预期,而且打印可以发现数据全为0 。
分析:实际上,mmap的时候只是申请了一块vma,读的时候发生一次缺页异常,映射到0页,所有内存没有分配,当再次写这个页面的时候,发生了COW分配新页(cow中分配新页的时候会判断原来的页是否为0页,如果为0页就直接分配页然后用0填充) 。
五,总结匿名映射缺页异常是我们遇到的一种很常用的一种异常,对于匿名映射,映射完成之后,只是获得了一块虚拟内存,并没有分配物理内存,当第一次访问的时候:如果是读访问,会将虚拟页映射到0页,以减少不必要的内存分配;如果是写访问,则会分配新的物理页,并用0填充,然后映射到虚拟页上去 。而如果是先读访问一页然后写访问这一页,则会发生两次缺页异常:第一次是匿名页缺页异常的读的处理,第二次是写时复制缺页异常处理 。


推荐阅读