mmap是如何分配虚拟内存的——关于mmap和virtual_memory的思考

mmap是如何分配虚拟内存的——关于mmap和virtual memory的思考

之前看CSAPP这本书,看到mmap也能够分配virtual memory,但是我之前的理解是mmap就是将文件映射到用户的内存空间,这个技术怎么能够用来分配虚拟内存?

我之前的理解是malloc 使用sbrk or brk来分配内存。于是我写了这样一个小程序来验证但是出乎我的意料。

image-20230217120735838

image-20230217120858822

malloc并没有调用sbrk或者brk来分配,它分配的内存地址并不在堆上。

于是使用strace来查看系统调用,发现其使用mmap来分配这段内存

image-20230217120644936

csapp里面给出了mmap的介绍:

image-20230217133350439

和ChatGPT聊了聊,对mmap有了更多的理解:

  • malloc进行虚拟内存的分配的时候,如果heap没有free block,可能会调用srbk增大heap的大小,也有可能调用mmap来分配一段虚拟内存,但是调用mmap分配得到内存并不是在堆上。

  • 如果mallo调用的是 sbrk或者brk来获得新的虚拟内存,如果调用free来释放这段内存。free只是简单将这段内存block Mark为free,也就是接下来的malloc分配器可以重新使用这个block,heap大小并不会减少,也就是通过malloc分配得到的内存不会交还给OS。但是如果malloc调用的是mmap,当调用free后,其会借着调用 munmap来释放这段内存,也就是实际上得到的physical memory会交还给OS。

  • sbrk和brk使用demand-zero技术。当进程从操作系统申请新的内存时候,操作系统并不会立即分配physical memory。相反其只是简单设置了对应虚拟地址的PTE,并且将PTE设置为demand-zero。如果进程接下来需要使用这一段内存,通过虚拟地址翻译,其会发现这个PTE设置为demand-zero,于是发生了page fault,陷入OS内核,OS内核这时候才会将真正的physical address map到这个virtual address。

回到最开始的问题,mmap是如何进行虚拟内存的分配。

首先,mmap有两种模式,file-back和anonymous mapping。这两种模式下,都是依赖于操作系统的page fault。

如果是file-back mapping,那么就相当于把文件映射到拥护态,参数fd应该是相应的文件描述符。此时OS会分配一部分内存,将文件内容拷贝到相应的虚拟地址空间。注意,这里不是demand-zero,因为read磁盘还是开销很大的,OS遇到可能会使用一些策略每次page fault来多读取一些内存。

在file-back mapping下还有一个非常令人迷惑的参数——MAP_DIRECT flag。这个flag用于绕过操作系统的page cache,也就是当page fault发生时,OS会直接从磁盘读取相应的内存并保存到相应的用户态地址,而不需要先保存到kernel 的cache buffer,但我们使用MAP_DIRECT flag,必须注意fd,也就是文件打开必须使用 O_DIRECT

anonymous mapping就是本文真的想谈的,但是实际上,这个mode反而更加简单。设置MAP_ANON flag,就可以使用anonymous mapping,调用mmap不需要提供文件描述符,相当于没有真正的back-file。操作系统会使用demand-zero技术,直接分配一段map的virtual address,当进程访问这一段地址时候,就会处罚page fault,然后OS再进行相应的physical address mapping。

mmap还可以用于进程之间的share memory。但是这里就不进一步去研究了。

posted @ 2023-02-17 14:22  kalice  阅读(417)  评论(0编辑  收藏  举报