当前位置:首页 > 行业动态 > 正文

分页存储管理结构c

分页存储管理将内存划分为等大页框,逻辑地址分为页号与偏移,通过页表映射物理页,消除外碎片,提升内存利用率,但存在内碎片及页

分页存储管理结构详解

分页存储管理的基本概念

分页存储管理是操作系统内存管理的核心机制之一,通过将进程的逻辑地址空间划分为固定大小的页(Page),并将物理内存划分为相同大小的页框(Frame),实现逻辑地址到物理地址的映射,这种机制解决了连续内存分配的碎片问题,提升了内存利用率。

核心特点

  1. 固定大小的页和页框:通常为4KB、2MB或更大(现代系统支持巨大页)。
  2. 逻辑地址分解:逻辑地址分为页号(Page Number)页内偏移(Offset)
  3. 页表映射:通过页表(Page Table)建立页号到页框的映射关系。

逻辑地址到物理地址的转换

分页系统中,逻辑地址的转换需要以下步骤:

  1. 分解逻辑地址

    • 逻辑地址 = 页号(高位) + 页内偏移(低位)。
    • 逻辑地址 0x0040(假设页大小为16字节):
      • 页号 = 0x0040 / 16 = 0x0004(第4页)
      • 偏移 = 0x0040 % 16 = 0x0(页内第0字节)
  2. 查询页表

    • 页表是一个数组,索引为页号,值为对应的页框号。
    • 页表项 PT[4] = 0x05,表示第4页映射到第5号页框。
  3. 生成物理地址

    • 物理地址 = 页框号 × 页大小 + 偏移。
    • 页框号 0x05,偏移 0x0,则物理地址为 0x0500

示例表格
| 逻辑地址 | 页号 | 偏移 | 页框号 | 物理地址 |
|———-|——|——|——–|———-|
| 0x0040 | 4 | 0x0 | 0x05 | 0x0500 |
| 0x006A | 4 | 0xA | 0x05 | 0x050A |

分页存储管理结构c  第1张


页表结构与实现

页表是分页系统的核心数据结构,其设计直接影响内存访问效率。

  1. 基本页表

    • 每个进程维护一个独立页表,包含所有页的映射信息。
    • 缺点:页表占用大量内存(32位系统需要4MB页表)。
  2. 多级页表(以二级为例):

    • 将页表分为外页表内页表,外页表存储内页表的物理地址。
    • 优点:减少内存占用,支持稀疏地址空间。
    • 示例
      • 逻辑地址分解为:外页号 + 内页号 + 偏移。
      • 外页表项指向内页表,内页表项指向页框。
  3. 哈希页表

    • 使用哈希表替代数组,减少内存浪费。
    • 适用场景:稀疏地址空间或超大页系统。

页面置换算法(C语言实现)

当物理内存不足时,需将内存中的页交换到磁盘(即缺页中断),并选择一个页替换出去,以下是常见算法的C语言实现思路:

  1. FIFO(先进先出)

    int pageQueue[MAX_FRAMES]; // 队列存储页框号
    int queueHead = 0;
    void replacePageFIFO(int newPage) {
        int oldPage = pageQueue[queueHead];
        pageQueue[queueHead] = newPage;
        queueHead = (queueHead + 1) % MAX_FRAMES;
        // 将oldPage对应的页写回磁盘
    }
  2. LRU(最近最少使用)

    int pageAccessTime[MAX_FRAMES]; // 记录访问时间戳
    void replacePageLRU(int newPage) {
        int oldestPage = 0;
        for (int i = 1; i < MAX_FRAMES; i++) {
            if (pageAccessTime[i] < pageAccessTime[oldestPage]) {
                oldestPage = i;
            }
        }
        // 替换oldestPage,更新新页的时间戳
    }

分页存储的C语言模拟实现

以下是一个简单的分页系统模拟框架:

#define PAGE_SIZE 4096 // 4KB
#define NUM_FRAMES 100 // 物理页框数
#define PAGE_TABLE_SIZE 1024 // 逻辑页数
typedef struct {
    int frameNumber; // 页框号
    int valid;       // 有效位(标记是否在内存中)
} PageTableEntry;
PageTableEntry pageTable[PAGE_TABLE_SIZE];
int memoryFrames[NUM_FRAMES]; // 存储当前加载的页框
int nextFreeFrame = 0;        // 下一个空闲页框
// 逻辑地址转换函数
int translateAddress(unsigned int logicalAddress) {
    int pageNum = logicalAddress / PAGE_SIZE;
    int offset = logicalAddress % PAGE_SIZE;
    if (pageNum >= PAGE_TABLE_SIZE || !pageTable[pageNum].valid) {
        // 缺页中断处理(如调用页面置换算法)
        return -1; // 错误标志
    }
    int frameNum = pageTable[pageNum].frameNumber;
    return frameNum  PAGE_SIZE + offset; // 物理地址
}

分页存储的优化策略

  1. TLB(快表)加速

    • TLB是页表的缓存,存储最近使用的页表项。
    • 命中率优化:增大TLB容量或采用多级TLB。
  2. 反向页表

    • 按物理页框存储映射关系,减少内存占用。
    • 适用场景:超大规模内存系统。
  3. 巨大页支持

    • 支持2MB、1GB等超大页面,减少页表项数量。
    • 优势:降低TLB缺失率,提升性能。

FAQs

Q1:分页存储管理与分段存储管理的区别是什么?
A1:分页和分段是两种不同的内存管理方式:

  • 分页:逻辑地址按固定大小划分,无需对齐,无外部碎片但可能有内部碎片。
  • 分段:按程序逻辑单元划分(如函数、数组),段大小不固定,无内部碎片但可能有外部碎片。
  • 本质区别:分页面向硬件(提高效率),分段面向程序逻辑(提高可读性)。

Q2:如何选择页面置换算法?
A2:选择算法需综合考虑场景和性能需求:

  • FIFO:实现简单,但可能替换常用页(Belady异常)。
  • LRU:接近理想算法,但需要记录访问顺序(开销大)。
  • LFU:适合访问频率差异大的场景,但可能忽略时间局部性。
  • 实际策略:现代系统常结合多种算法(如LRU-K、Clock算法)或使用
0