最近在一次采访中,我被问到mmap是否可以直接以二进制模式映射程序;没有页面参考。
我认为这是不可能的,因为它
允许应用程序将文件映射到内存中,这意味着存在 存储器地址与存储器中的字之间的一对一对应关系 文件。程序员然后可以直接通过内存访问文件, 与任何其他内存驻留数据相同 - 它是偶数 可以允许写入内存区域以透明映射 回到磁盘上的文件
访问没有涉及分页的文件听起来不对。
我仍然想知道mmap是否可以通过页面方式以任何其他方式将文件映射到内存中。
=====
the page way
=====
页面是可以具有不同内存的最小内存单位 权限和行为。因此,页面是构建块 内存映射,而后者又是内存的构建块 进程地址空间。 mmap()系统调用在页面上运行。都 addr和offsetparameters必须在页面大小上对齐 边界。也就是说,它们必须是页面大小的整数倍。
因此,映射是页面的整数倍。如果 调用者提供的len参数未在页面上对齐 边界 - 可能是因为底层文件的大小不是倍数 页面大小 - 映射向上舍入到下一个整页
答案 0 :(得分:1)
如果我们使用维基百科page的定义:
,所有内存映射都涉及页面级映射页面,内存页面或虚拟页面是固定长度的连续虚拟内存块,由页表中的单个条目描述。它是虚拟内存操作系统中内存管理的最小数据单元。
如man 2 mmap
手册页中所述,
mmap()在调用进程的虚拟地址空间中创建一个新映射。
映射由页表中的条目定义。
因此,基本上,mmap()
是一种在页面级别管理虚拟内存的工具。
面试官可能试图找出你是否理解低级I / O(read()
,write()
)和文件支持的内存映射行为之间的区别。
如果使用O_DIRECT
标志打开文件,内核会尝试将数据直接传输到用户空间缓冲区,绕过页面缓存。
由于内存映射的工作方式,使用带有open()
标志或不带O_DIRECT
标志的后备文件MAP_SHARED
对内存映射没有影响。
(MAP_PRIVATE
/ PROT_NONE
标志是否影响映射的访问部分使用的内存是否保留在页面缓存中。通常,Linux内核使用写时复制方法:页面在页面缓存中保持只读,直到第一次写入访问。此时,私有映射被复制到新页面(或被逐出),共享映射标记为read-写。它有点复杂,但效率很高。但是,所有这些都依赖于虚拟内存分页。)
甚至可以构建一个完全没有后备的内存映射(SIGBUS
映射)。对映射的任何访问都会导致内核生成O_DIRECT
信号(尝试访问的线程),该信号可以被进程捕获。信号处理程序可以解码并跳过指令,从而模拟存储器访问。它甚至可以使用Map<String, Student> students = new HashMap<String, Student>();
Student maryIn = new Student();
maryIn.setName("Mary");
students.put(maryIn.getName(), maryIn);
Student maryOut = students.get("Mary");
从文件中读取一个或多个字节。同样,映射基于虚拟内存,因此是页面;没有用于映射的RAM,而是模拟了所有访问。这很少使用,因为它难以想象地慢。
答案 1 :(得分:0)
分页(至少在现代操作系统和体系结构上) 机制通过物理内存进行管理。
我建议您read more关于此主题,但基本上使用虚拟物理地址寻址) >地址。
物理和虚拟地址之间的映射通常使用MMU在硬件中完成,并使用 pages 进行组织。使用此概念,内存页面定义了一系列物理和虚拟地址之间的映射。
操作系统还在低级页面管理上方添加了几个层,mmap
是分页系统的用户界面,允许您操作页面。
特别是,它允许您将内存页面(请记住,一系列虚拟地址)映射到物理内存以外的其他内容,例如存储在硬盘驱动器上的文件。
总之,你可以使用内存的唯一方式是通过这个分页系统,所以为了回答你的问题,访问某些东西没有任何意义(作为文件,物理内存或其他任何东西) )“除了页面方式以外的任何其他方式”。