zoukankan      html  css  js  c++  java
  • 内存的分页管理方式解释

    今天在思考一个可能由page table引发的Linux操作系统内存报警问题时发现基础知识缺失的太多,因此找了几本操作系统相关的书复习了一下,在这里记下来。

    首先上一幅32位寻址空间的虚拟地址结构图:(仅适用于一级页表,页面大小为4KB)

    前12位表示页内偏移量,后20位表示页号,可寻址2^20=1M个页,假如页面大小为4KB,那么就能寻址4GB的虚拟地址。

    那么这样一个32位的虚拟地址是如何转换为物理地址的呢?

    下图说明了一切:

    图1.分页系统的地址变换机构 --摘自《计算机操作系统》汤小丹版

    寻址步骤解析:

    1.首先假设虚拟地址为A,页面大小为L,则可以通过以下公式迅速计算出相应的页号P和页内偏移量d:

    P=INT [A/L] --除法取整
    d=A%L  --求余
    

    2.得到P和d之后,使用P与页表寄存器中的寄存的页表始址(一个物理地址),进行逻辑运算得到页表项的具体位置。(其实就是通过页表始址找到页表页,再在里边找到页号)

    3.在此页表项中取到后半截的块号--通过块号得到块的物理始址,通过这个物理始址与页内偏移量相加得到真正的物理地址。

    整个过程很简单,就两个加法,两次寻址。

    举例说明:

    一个页表的结构如下所示:(这里省了标识页表的始址,直接给了页表的内容)

    页号    块号
    0        3
    1        2
    2        0
    3        1

    假设有一个虚拟地址0x000B,页面大小为4KB(0x1000),那么:

    1.P=0x000B/0x1000=0; d=0x000B%0x1000=0x000B;因此页号为0,页内偏移量为0x000B

    2.通过与寄存器的逻辑运算找到如上页面的0页号,发现0号对应物理块号是3

    3.3*0x1000+0x000B=0x300B

    因此真实的物理地址就是0x300B。

    拓展知识:

    由于页表空间必须是连续的内存地址,这样的开销在32位分页系统中几乎是不可接受的,因此我们一般采用如下两种办法解决此问题:

    1.多级页表,即页表的页表,这样页表可以离散的分布于内存之中,不必是连续内存,64位寻址空间的分页系统常见3级页表,32位的常见两级页表。

    2.只缓存一部分的页表,其他页表部分在外存中,根据需要调入,这样解决了页表空间占用的问题;对于多级页表,其外部页表必须调入内存,页表则可以只缓存一部分。

    现在常见的64位操作系统一般采用多级页表的方式,大多数为3级页表,其实就是页表3级索引,因此CPU多出了2个页表寄存器来记录多级页表的物理始址,但是本质与一级页表寻址方式类似。

    自2.6.11内核版本以来,Linux采用4级页表的分页方式(9+9+9+12)。

    在64位分页系统中,由于可寻址范围已经大大扩展,因此所有的页目录和页表都已被存入内存。

    对于用户空间和内核空间,以及高端内存、低端内存还有线性映射、非线性映射等概念,在64位分页系统中应当全部舍弃,除非你是研究内核的。

    最后再放一个段页式逻辑地址-->线性地址(虚拟地址)-->物理地址的转换图:

  • 相关阅读:
    频率和相位有什么关系
    DMA缓冲区乒乓操作的处理
    深入了解DSP与ARM的区别与联系
    python 里 np.array 的shape (2,)与(2,1)的分别是什么意思,区别是什么?(2020年修订)
    手写promise
    axios源码学习记录
    redux 之isPlainObject
    redux教程之源码解析3applyMiddleware(分析在注释中)
    redux教程之源码解析2 combineReducers(分析在注释中)
    redux教程之源码解析createStore
  • 原文地址:https://www.cnblogs.com/leohahah/p/6921731.html
Copyright © 2011-2022 走看看