页表和多级页表

我们在c和c++里看到的地址都是操作系统虚拟出来的,%p打印出来的也是虚拟地址,物理内存由操作系统统一管理.操作系统负责把虚拟地址映射到物理内存.

那么为什么要用到虚拟内存呢:

1,因为如果每个进程都访问物理内存的话,造成不可控性.如果进程有访问内存的权力,他就会把自己的数据存到内存上,但是他并不知道哪片内存被使用,那一片未被使用.所以在多个进程的情况下,数据会混乱,所以物理内存由操作系统管理,进程没有权限访问.

2,操作系统并不能预先知道这个进程有多大,这个进程运行多少时间,应该给他分配多少空间(如果分配的少了,不够进程的运行,如果分配的大了,则会导致内存空闲).所以进程给每个进程都虚拟出来一个4G的内存(32位操作系统上),如果进程需要保存数据或者开辟内存,操作系统通过虚拟地址就能知道,并在物理内存上进行操作.这样操作系统就能知道一个进程到底需要多少内存空间.

页表(内存管理单元)

虚拟地址不是直接匹配到物理内存的,而是通过页表把虚拟地址映射到物理内存.

虚拟地址以页面为单位,将虚拟地址划分成多个页面,在物理内存上对应的是块,一个页号对应一个块号,分别把虚拟地址和物理地址划分成一小部分作用很多,例如在虚拟地址里,当需要用到物理内存的时候,操作系统才会映射,并不是所有的页面都会被映射,在物理内存上,将物理内存分成一个个小块可以提高内存的使用率.

虚拟地址的页面一般以512byte~8k之间,windows下,页面是4k.
 页号对应的块号加业内偏移就是物理内存...每个进程都有页表,页表起始地址和页表长度的信息在进程不被CPU执行的时候,存放在其PCB内。 

 虚拟地址/页面=页表号

虚拟地址%页面=页内偏移   

通过页表号找到块号就能知道数据储存在内存的哪个块,块号再加上页内偏移就是数据存储的位置.

页表的大小:4G的虚拟内存可以分100万个页面,同样一个页面要对应一个块.所以一共需要100万个页表项,而且每个进程都有一个页表,假设一个页表项占用1byte,那么100万个要占用1M空间,但是不是所有的页表项都有用,有用的只是一小部分.所以保存所有的页表项并不明智.

多级页表:

以下引用其他优秀博客https://blog.csdn.net/forDreamYue/article/details/78887035

绝大多数都不需要,比如,一个需要12MB的进程,底端是4MB程序正文,后面是4MB数据,顶端是4MB堆栈,在数据顶端上方和堆栈之间是大量根本没有使用的空闲区。

虽然在图中的地址空间超过100万个页(1024个二级页表,每个二级页表有1024个页),实际上只需要四个页表:顶级页表以及0~4M、4M~8M和顶端4M的二级页表。顶级页表中1021(1024-3)个表项的“在/不在”位都被设为0,当访问它们时强制产生一个页面失效。


图中的顶级页表项的PT1有10位,代表顶级页表有2^10=1024个页表项(但大多的“在/不在”位都被设为0,因为没有用到),PT2有10位,代表二级页表有2^10=1024个页表项,一个页表项对应一个页面,也就是该页表项存储了虚拟地址的页帧号,用该页帧号加上Offset,就构成了物理地址。


举个例子,考虑32位虚拟地址0x00403004(十进制4206596),它位于数据部分12292字节处。它的虚拟地址对应PT1=1,PT2=2,Offset=4。MMU首先用PT1作为索引访问顶级页表得到表项1,它的地址范围是在它的4M块内的12288~16383(即绝对地址4206592~4210687)。这个表项含有虚拟地址0x00403004所在页面的页帧号。如果该页面不再内存中,页表表项中的“在/不在”位将是0,引发一次页面失效。如果该页面在内存中,从二级页表中得到的页帧号将与偏移量,也就是4结合构成物理地址。该地址被放到总线上并送到内存中。

对于大多数进程来说,多级页表是在节省空间,特殊情况,如果一个进程是4G,一级页表需要1M存储页表,而多级页表例如二级页表,因为1024个二级页表都能用到,所以都要储存起来,除此之外,还需要多存储一个大小为1024个页面的页表目录.

通常情况下多级页表可以节省存储空间,但是增加了寻址次数,延长了访问时间

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是操作系统中用来记录虚拟内存地址与物理内存地址映射关系的数据结构,其实现方式因操作系统不同而异。以下是一个简单的页代码实现示例,供参考: ```c #define PAGE_SIZE 4096 // 页大小为 4KB #define PAGE_NUM 1024 // 页项数为 1024 struct page_table_entry { unsigned int present : 1; // 页是否存在 unsigned int writeable : 1; // 页是否可写 unsigned int user_access : 1; // 用户是否有访问权限 unsigned int write_through : 1; // 是否写直达 unsigned int cache_disabled : 1; // 是否禁用缓存 unsigned int accessed : 1; // 是否被访问过 unsigned int dirty : 1; // 是否被修改过 unsigned int zero : 1; // 保留位 unsigned int global : 1; // 全局页标志位 unsigned int available : 3; // 空闲可用位 unsigned int page_frame : 20; // 物理页框号 }; struct page_table_entry page_table[PAGE_NUM]; // 初始化页 // 将虚拟地址映射到物理地址 void map_virtual_to_physical(unsigned int virtual_address, unsigned int physical_address) { unsigned int page_index = virtual_address / PAGE_SIZE; // 计算页号 page_table[page_index].present = 1; // 设置页存在 page_table[page_index].writeable = 1; // 设置页可写 page_table[page_index].user_access = 1; // 设置用户可访问 page_table[page_index].write_through = 0; // 不写直达 page_table[page_index].cache_disabled = 0; // 不禁用缓存 page_table[page_index].accessed = 0; // 未被访问过 page_table[page_index].dirty = 0; // 未被修改过 page_table[page_index].zero = 0; // 保留位清零 page_table[page_index].global = 0; // 非全局页 page_table[page_index].available = 0; // 空闲可用位清零 page_table[page_index].page_frame = physical_address / PAGE_SIZE; // 计算页框号 } ``` 以上代码实现了将虚拟地址映射到物理地址的功能,具体实现方式可能会因操作系统的不同而有所差异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值