20.内存换入-请求调页

【README】

1.本文内容总结自 B站 《操作系统-哈工大李治军老师》,内容非常棒,墙裂推荐;

2.操作系统关于内存管理的核心是基于虚拟内存的分段和分页管理
3.而用内存换入和换出实现虚拟内存 ;


【1】虚拟内存

1)段页同时存在的内存管理图像


2)用户眼里的内存(就是虚拟内存)

 

【图解】

  • 用户可以随意使用该内存(虚拟内存),就像单独拥有4G内存;
  • 每个进程都有对应一个虚拟内存;
  • 虚拟内存中存放了程序段,包括数据段,代码段,栈段等;
  • 虚拟内存如何映射到物理内存,用户全然不知道;
  • 操作系统利用虚拟内存与物理内存的映射来给用户提供这种4G内存的假象或图像;

3)换入
换入就是在虚拟内存与物理内存的映射上进行工作;


【2】用换入换出实现大内存

  • 问题:虚拟内存4G,但物理内存实际只有1G,怎么办 ?
  • 解决方法:内存换入换出;

【2.1】换入实例

【图解】

  • 用户程序都在磁盘上,包括它的代码段,数据段,共计4G大小;
  • 场景1:执行到0~1G,操作系统把磁盘上0~1G的代码段 换入 到物理内存,并建立虚拟内存与物理内存的映射;用户可以随便使用0~1G虚拟内存空间;
  • 场景2:执行到3G~3.5G,操作系统把磁盘上3G~3.5G的数据段   换入  到物理内存,并建立虚拟内存与物理内存的映射;用户可以随便使用3G~3.5G虚拟内存空间;

【小结】
1)以上2个场景,用户感觉到 可以使用 0~1G范围的内存,也可以使用3G~3.5G范围的内存,用户感觉机器可以使用的内存空间是0~4G(但实际物理内存只有1G,却给了用户4G内存的假象);

2)请求的时候才映射(指令执行时需要寻址到3G~3.5G)
请求的时候才换入,用这种方法可以实现 0~4G 的一个规整的虚拟内存;


【2.2】请求调页(换入)

1)请求换入,建立映射(虚拟内存与物理内存的映射 );

  • 即 请求调入物理内存页,并建立虚拟内存与物理内存页的映射;


【图解】请求调页具体步骤
指令的逻辑地址为 段号+偏移(cs:ip);

  • 步骤1: 操作系统执行指令 load [addr], 根据逻辑地址addr的段号从段表中查询段基址(虚拟内存地址);
  • 步骤2: MMU根据段基址计算出逻辑页号,发现逻辑页号在页表中没有记录(如拿着3.5G内存地址的逻辑页号 到 0~1G中的页表查找 物理页号,肯定查无记录);
  • 步骤3: 因为页表中没有记录(缺页),或MMU发现缺页,则MMU发出页错误中断请求(缺页中断请求)(设置中断请求触发器的某1位为1),等待cpu处理;
  • 步骤4: CPU处理中断,执行中断处理程序,即执行页错误处理程序;
  • 步骤5: 页错误处理程序从磁盘找到需要的页,并读入到空闲物理内存页,并建立虚拟内存与物理内存的映射关系(在页表中添加一条记录);
  • 步骤6: 中断处理程序执行完成后,即请求调页完成后,CPU再次执行 load [addr] 指令,就能够正确把逻辑地址 addr 翻译到物理地址了;

综上:应用请求调页或物理内存页换入,就可以实现4G大小的虚拟内存供用户随便使用;

  • 补充1:MMU是一个硬件,可以代替程序把逻辑地址立即转为物理地址(相比软件,MMU硬件的地址翻译效率更高);
  • 补充2:虽然对用户来说感觉到的是4G内存,但使用过程中存在系统响应慢的情况,原因在于访问某些内存地址空间时,由于缺页可能导致操作系统请求调页(需要从磁盘读取数据到物理内存,比较耗时),调页需要耗费时间的;

2)问题:采用请求调页而不是请求调段,原因是什么 ?


段比页占用内存空间更大,请求调页占用内存空间小,内存利用率高;
当然,也可以请求调段,只不过性能可能偏低;


 【3】请求调页代码实现

1)一个实际系统的请求调页
请求调页代码,从缺页中断开始; 14号中断是缺页中断;

// 操作系统启动时,初始化14号中断(缺页中断)的中断处理程序为 page_fault 
void trap_init(void) 
{
	set_trap_gate(14, &page_fault);
}
// 修改idt表,新增中断与中断处理程序的关联关系 
#define set_trap_gate(n, addr)
	_set_gate(&idt[n], 15, 0, addr);  

 2)处理中断 page_fault

 【图解】

  • cr2寄存器: 用于存储页错误线性地址,记录是哪一页缺页了;(线性地址就是虚拟地址)
  • Call _do_no_page: 调用缺页处理函数 _do_no_page(),参数是 %cr2寄存器的值(注意压栈了)

3)缺页函数 do_no_page()
从磁盘中找到需要的页,并读入空闲的物理内存页,建立虚拟内存与物理内存的映射关系(页表);

// 缺页函数 do_no_page() 
//  在 linux/mm/memory.c 中
void do_no_page(unsigned long error_code, unsigned long address) 
{	
	// 获取逻辑页号
	address &= 0xfffff000; 
	tmp = address - current->start_code; // 页面对应偏移量 
	if( !current->executagle || tmp >= current->end_data ) {
		get_empty_page(address); return ;
	}
	// 换入第1步: 申请一个物理空闲页 
	page = get_free_page();
	// 换入第2步: 从磁盘(或当前进程可执行文件所在设备 i_dev)上读取缺页数据到物理空闲页 (block read) 
	bread_page(page, current->executable->i_dev, nr); 
	// 换入第3步: 把物理页与虚拟地址建立映射(在页表中新增一条映射记录) 
	put_page(page, address);  
} 

 补充:请求调页换入的3个步骤(非常重要*):

  • 步骤1:申请空闲的物理内存页;
  • 步骤2: 从磁盘读取缺页数据到物理内存页;
  • 步骤3: 建立虚拟内存与物理内存页的映射关系,即修改页表,新增一条映射记录;

4)put_page() 修改页表,新增一条映射记录 (仅了解)

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值