文件的 mmap 可以通过页面级映射以外的任何其他方式完成吗?

mmap of files can be done in any other way except page level mapping?

最近在一次采访中,有人问我mmap是否可以直接以二进制方式对程序进行映射;没有页面引用。

我认为这是不可能的,因为它

allows an application to map a file into memory, meaning that there is a one-to-one correspondence between a memory address and a word in the file. The programmer can then access the file directly through memory, identically to any other chunk of memory-resident data—it is even possible to allow writes to the memory region to transparently map back to the file on disk

在不涉及分页的情况下访问文件听起来是错误的。

我仍然想知道除了页面方式之外,mmap 是否可以通过任何其他方式映射内存中的文件。

=====
the page way
=====

The page is the smallest unit of memory that can have distinct permissions and behavior. Consequently, the page is the building block of memory mappings, which in turn are the building blocks of the process address space. The mmap( ) system call operates on pages. Both the addr and offsetparameters must be aligned on a page-sized boundary. That is, they must be integer multiples of the page size.

Mappings are, therefore, integer multiples of pages. If the len parameter provided by the caller is not aligned on a page boundary—perhaps because the underlying file's size is not a multiple of the page size—the mapping is rounded up to the next full page

分页是(至少在现代 OSes 和体系结构上) 通过物理内存管理的机制。

我建议你在这个问题上read more,但基本上物理内存(使用物理地址寻址)是从内核和用户space 使用 虚拟 地址。

物理虚拟地址之间的映射通常使用MMU在硬件中完成,并使用页数。使用这个概念,内存页面定义了一系列物理地址和虚拟地址之间的映射。

OS 还在 low-level 页面管理之上添加了几层,mmap 是分页系统的用户界面,允许您操作页面。 特别是,它允许您将内存页(记住,虚拟地址范围)映射到物理内存以外的其他东西,例如存储在硬盘驱动器上的文件。

总而言之,唯一使用内存的方式是通过此分页系统,因此要回答您的问题,访问某些内容(作为文件,物理内存或其他任何东西)"in any other way than the page way".

所有内存映射都涉及页级映射,如果我们使用维基百科的定义page

A page, memory page, or virtual page is a fixed-length contiguous block of virtual memory, described by a single entry in the page table. It is the smallest unit of data for memory management in a virtual memory operating system.

man 2 mmap 手册页所述,

mmap() creates a new mapping in the virtual address space of the calling process.

映射由页面中的条目定义 table。

所以,本质上,mmap()是一个在页面级别管理虚拟内存的工具。


面试官可能想问你是否理解low-level I/O (read(), write()) 和file-backed 内存映射的区别行为。

如果您使用 O_DIRECT 标志打开文件,内核会尝试将数据直接传输到用户空间缓冲区,绕过页面缓存。

由于内存映射的工作方式,支持文件 open() 使用或不使用 O_DIRECT 标志对内存映射没有影响。

(MAP_SHARED/MAP_PRIVATE 标志会影响用于映射的访问部分的内存是否保留在页面 cache 中. 通常,Linux 内核使用 copy-on-write 方法:页面在页面缓存中保持 read-only 直到第一次写访问。此时,私有映射被复制到新页面(或evicted),共享映射标记为read-write。有点复杂,但效率很高。但是,这一切也都依赖于虚拟内存分页。)

甚至可以构建一个完全没有支持的内存映射(PROT_NONE 映射)。对映射的任何访问都会导致内核生成一个 SIGBUS 信号(给尝试访问的线程),该信号可以被进程捕获。信号处理程序可以解码并跳过指令,从而模拟内存访问。它甚至可以使用 O_DIRECT 从文件中读取一个或多个字节。同样,映射是基于虚拟内存的,因此也是基于页面的;只是没有用于映射的 RAM,而是模拟所有访问。这个很少用,因为慢得难以想象