c - 是否只有在出现页面错误时才会出现虚拟内存区域结构?

标签 c linux linux-kernel

虚拟内存对我来说是一个相当复杂的话题。我试图理解它。这是我对 32 位系统的理解。示例 RAM 仅为 2GB。我试过阅读很多链接,目前我没有信心。我希望你们帮助我理清我的概念。请承认我的观点,并请回答您认为不对的地方。我的观点中也有一个令人困惑的部分。所以,这里开始总结。

  • 每个进程都认为它只是在运行。它可以访问4GB的内存——虚拟地址空间。
  • 当进程访问虚拟地址时,它会通过 MMU 转换为物理地址。
    这个 MMU 是 CPU 的一部分 - 一个硬件。
  • 当 MMU 无法将地址转换为物理地址时,它会引发页面错误。
  • 出现页面错误时,会通知内核。内核检查 VM 区域结构。如果它可以找到它 - 可能在磁盘上。它会做一些page-in/page-out。并在 RAM 上获取此内存。
  • 现在MMU将再次尝试并且这次会成功。
  • 如果内核找不到地址,它会发出一个信号。例如,无效访问将引发 SIGSEGV。

  • 混淆点。
  • 页表是否在内核中维护?这个 VM 区域结构有一个页表?
  • MMU 如何在物理 RAM 中找不到地址。假设它转换为 RAM 中的某个错误地址。代码仍然会执行,但它将是一个错误的地址。 MMU 如何确保它正在读取正确的数据?它是否每次都咨询内核VM区域?
  • 是映射表 - 虚拟到物理在 MMU 内。我读过它是由单个进程维护的。如果它在一个进程内,为什么我看不到它。
    或者如果是MMU,MMU是如何生成地址的——是不是Segment+12位移位->页帧号,然后加上偏移量(位-1到10)->给出一个物理地址。
    这是否意味着对于 32 位架构,我心中有这个计算。我可以从虚拟地址确定物理地址。
  • cat/proc/pid_value/maps.这向我展示了 vmarea 的当前映射。基本上,它读取 Vmarea 结构并打印它。这意味着这很重要。我无法将这件作品放在完整的图片中。执行程序时会生成 vmarea 结构。当 MMU 无法转换地址即页面错误时,VMAREA 是否只出现在图片中?当我打印 vmarea 时,它会显示地址范围、权限和映射到文件描述符以及偏移量。我确信这个文件描述符是硬盘中的一个,偏移量是那个文件的。
  • high-mem 概念是内核不能直接访问大于 1 GB(大约)的内存区域。因此,它需要一个页表来间接映射它。因此,它会临时加载一些页表来映射地址。 HIGH MEM 是否每次都会出现。因为Userspace可以通过MMU直接转换地址。在什么情况下,内核真的要访问高 MEM。我相信内核驱动程序将主要使用 kmalloc。这是直接内存+偏移地址。在这种情况下,实际上不需要映射。因此,问题在于内核需要访问 High Mem 的场景。
  • 处理器是否专门提供了 MMU 支持。没有MMU支持的就不能运行Linux?
  • 最佳答案

    • Does Page table is maintained in Kernel? This VM area struct has a page table ?


    是的。不完全是:每个进程都有一个 mm_struct,其中包含一个列表 vm_area_struct 's(代表抽象的、独立于处理器的内存区域,又名映射),以及一个名为 pgd 的字段,它是指向特定于处理器的页表的指针(其中包含每个页的当前状态:有效、可读、可写、脏等)。

    页表不需要是完整的,操作系统可以从 VMA 生成它的每一部分。

    • How MMU cannot find the address in physical RAM. Let's say it translates to some wrong address in RAM. Still the code will execute, but it will be a bad address. How MMU ensures that it is reading a right data? Does it consult Kernel VM area everytime?


    翻译失败,例如因为页面被标记为无效,或者尝试对只读页面进行写访问。

    • Is the Mapping table - virtual to physical is inside a MMU. I have read it that is maintained by an individual process. If it is inside a process, why I can't see it. Or if it is MMU, how MMU generates the address - is it that Segment + 12-bit shift -> Page frame number, and then the addition of offset (bits -1 to 10) -> gives a physical address. Does it mean that for a 32-bit architecture, with this calculation in my mind. I can determine the physical address from a virtual address.


    有两种常用的 MMU。其中一个只有一个TLB(Translation Lookaside Buffer),它是页表的缓存。当 TLB 没有尝试访问的翻译时,会生成 TLB 未命中,操作系统执行页表遍历,并将翻译放入 TLB。

    另一种 MMU 在硬件中执行页表遍历。

    在任何情况下,操作系统都会为每个进程维护一个页表,这将虚拟页号映射到物理帧号。这种映射可以随时更改,当页面被调入时,它映射到的物理帧取决于可用内存的可用性。

    • cat /proc/pid_value/maps. This shows me the current mapping of the vmarea. Basically, it reads the Vmarea struct and prints it. That means that this is important. I am not able to fit this piece in the complete picture. When the program is executed does the vmarea struct is generated. Is VMAREA comes only into the picture when the MMU cannnot translate the address i.e. Page fault? When I print the vmarea it displays the address range , permission and mapped to file descriptor, and offset. I am sure this file descriptor is the one in the hard-disk and the offset is for that file.


    初步估计,是的。除此之外,内核可能会决定摆弄进程的内存的原因有很多,例如:如果存在内存压力,它可能会决定从某个随机进程中分出一些很少使用的页面。用户空间也可以通过 mmap() 操作映射, execve()和其他系统调用。

    • The high-mem concept is that kernel cannot directly access the Memory region greater than 1 GB(approx). Thus, it needs a page table to indirectly map it. Thus, it will temporarily load some page table to map the address. Does HIGH MEM will come into the picture everytime. Because Userspace can directly translate the address via MMU. On what scenario, does kernel really want to access the High MEM. I believe the kernel drivers will mostly be using kmalloc. This is a direct memory + offset address. In this case no mapping is really required. So, the question is on what scenario a kernel needs to access the High Mem.


    与其他问题完全无关。总之,高内存是一种能够在有限地址空间的计算机中访问大量内存的技巧。

    基本上,内核为其保留了有限的地址空间(在 x86 上,典型的用户/内核拆分为 3Gb/1Gb [进程可以在用户空间或内核空间中运行。当调用系统调用时,进程在内核空间中运行。到避免在每次上下文切换时切换页表,在 x86 上通常地址空间在用户空间和内核空间之间分割])。因此内核可以直接访问高达 ~1Gb 的内存。为了访问更多的物理内存,涉及到一些间接,这就是高内存的全部意义所在。

    • Does the processor specifically comes with the MMU support. Those who doesn't have MMU support cannot run Linux?


    笔记本电脑/台式机处理器带有 MMU。 x86 从 386 开始支持分页。

    Linux,特别是称为 µCLinux 的变体,支持没有 MMU (!MMU) 的处理器。许多嵌入式系统(ADSL 路由器,...)使用没有 MMU 的处理器。有一些重要的限制,其中包括:
  • 一些系统调用根本不起作用:例如 fork() .
  • 一些系统调用适用于限制和非 POSIX 符合行为:例如 mmap()
  • 可执行文件格式不同:例如 bFLT 或 ELF-FDPIC 而不是 ELF。
  • 堆栈不能增长,它的大小必须在链接时设置。

  • When a program is loaded first the kernel will setup a kernel VM-Area for that process is it? This Kernel VM Area actually holds where the program sections are there in the memory/HDD. Then the entire story of updating CR3 register, and page walkthrough or TLB comes into the picture right? So, whenever there is a pagefault - Kernel will update the page table by looking at Kernel virtual memory area is it? But they say Kernel VM area keeps updating. How this is possible, since cat /proc/pid_value/map will keep updating.The map won't be constant from start to end. SO, the real information is available in the Kernel VM area struct is it? This is the acutal information where the section of program lies, it could be HDD or physical memory -- RAM? So, this is filled during process loading is it, the first job? Kernel does the page in page out on page fault, and will update the Kernel VM area is it? So, it should also know the entire program location on the HDD for page-in / page out right? Please correct me here. This is in continuation to my first question of the previous comment.



    当内核加载程序时,它会根据可执行文件中的段(在 ELF 文件中可以使用 readelf --segments 看到)设置多个 VMA(映射),这些段将是文本/代码段、数据段等...在程序的生命周期中,动态/运行时链接器、内存分配器( malloc() ,也可以通过 brk() 扩展数据段)或直接由程序通过mmap() , shm_open() , 等等..

    VMA 包含生成页表所需的信息,例如它们告诉该内存是由文件支持还是由交换(匿名内存)支持。所以,是的,内核将通过查看 VMA 来更新页表。内核将在内存中分页以响应页面错误,并在内存压力时将内存调出。

    以 x86 无 PAE 为例:

    在没有 PAE 的 x86 上,线性地址可以分为 3 部分:前 10 位指向页目录中的一个条目,中间 10 位指向上述页目录条目所指向的页表中的一个条目。页表条目可能包含一个有效的物理帧号:物理地址的前 22 位。虚拟地址的底部 12 位是页面中的偏移量,该偏移量未转换为物理地址。

    每次内核调度不同的进程时,都会向 CR3 寄存器写入一个指向当前进程页目录的指针。然后,每次进行内存访问时,MMU 都会尝试查找缓存在 TLB 中的翻译,如果没有找到,它会查找一个从 CR3 开始执行页表遍历的翻译。如果仍然没有找到,就会引发 GPF 故障,CPU 切换到 Ring 0(内核模式),内核尝试在 VMA 中找到一个。

    Also, I believe this reading from CR, page directory->page-table->Page frame number-memory address this all done by MMU. Am I correct?



    在 x86 上,是的,MMU 执行页表遍历。在其他系统(例如:MIPS)上,MMU 仅比 TLB 多一点,在 TLB 未命中异常时,内核通过软件执行页表遍历。

    关于c - 是否只有在出现页面错误时才会出现虚拟内存区域结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20041212/

    相关文章:

    在 C++11 中调用 C 函数时,我可以将 std::vector 作为 FILE* 潜入吗?

    linux - 将 hash-sign-starting-string 参数传递给 shell 脚本

    linux-kernel - 使用 32 位操作执行 ioread/write64

    performance - 不同内核版本性能回归原因分析

    c - 让 : *** No rule to make target 'all' . 停止。 C/C++问题

    c - 不溢出的缓冲区溢出

    c - 无法理解 scullpipe 驱动程序中的 spacefree 函数

    c - 为什么当我启用 LTO/IPO 时 CMake 会设置 -no-fat-lto-objects?

    linux - 调制解调器管理器 : mmcli get signal strength

    在 Linux 中复制/移动文件并使用系统调用的 C 应用程序