程序如何在计算机运行的——操作系统内存管理

本篇基于大白话来进行说明,可能有些词并不会那么的准备,尽量用我的理解来说明,适合初学者,不适合进阶。看的是哈工大老师讲的,课程链接

当写完一个程序都会有一个main函数,作为函数入口,假设函数入口main的起始地址是0,在main函数调用了hello这个函数,函数要偏移40(这个也称相对地址、逻辑地址),如果物理内存中0-40这里可以分配给程序,把这个test程序加载到了内存中,这个test就可以在电脑上运行了。

//test
#include<iostream>
using namespace std;
void hello(){}
int main(){
	hello();
	return  0;
}

问题来了:每个程序的函数入口都是从0开始,可物理内存只有一个0起始位置,要怎么分配?解决之道(修改这个相对地址,又名重定位),重定位可以发生在编译的时候、载入的时候(一会还会介绍运行时重定位,也称为地址翻译),编译是直接把这个程序烧到板子上,启动就是在这个地址上。载入是看哪里能分配这个程序的大小,就分配,比如起始地址是1000,还是假设偏移40,那程序就以1000为起始入口,到1040结束(如下图),这样就解决了多个程序怎么加载到内存上问题。
在这里插入图片描述

问题又来了,当内存和磁盘交换进程空间的时候,如下面两张图,进程1的位置换了,可进程1的起始位置还是在原来的起始地址,这肯定就不对了呀,那要怎么解决呀?就是上文所要介绍的运行时重定位,在进程要加载到内存条的时候,运行的时候更改程序的起始位置和终止位置,这样也解决了进程交换的时候发生的问题。这些起始地址、终止信息信息保存在哪里呢?保存在PCB中(进程管理块),每一个进程都有一个PCB。PCB负责记录这些东西。
在这里插入图片描述
在这里插入图片描述

内存又分为固定分区和可变分区(首先适配、最佳适配、最差适配),在这里不探讨好坏,确实也分析不出来。不过最后操作系统这两种都没有选择选的是分页。

这样一个进程一个进程分配会产生外部碎片,所以提出了分页,记住哦物理内存是分页的,虚拟内存是分段的。
页号求解:起始地址/页面大小(通常是4KB) = 第几页
/4kb相当于右移12位,得到了页号在查页表找到页框是多少,页框+右移12位(转成十进制)就是物理地址存储的地方
在这里插入图片描述

多级页表
假如32位系统,页的大小是4KB,系统为每个进程都分配2^20B的页(4MB),这些页是放在页表的,页表是跟着进程进入内存的,系统有上百个进程,为每个进程提供4MB的空间,而且并不会全部用上,就造成了浪费。科学家想怎么能减少这些浪费呢?像每一本书都有目录,目录下面有小节,科学家们就发明了多级页表,把每个页表都装入2 ^ 10个页,不需要的页表就不放入就减少了内存空间的浪费,可是这样又多了一次打开页表速度又慢了下来,怎么提高速度呢?软件上已经没有办法再改进了,于是设计了个寄存器TLB,一般也叫快表,相当于页的缓冲区,如果在TLB找不到所需要的页再去查多级页表,TLB命中率还是很高的!

真正的操作系统内存管理——段页结合
程序员需要将程序分为一个段一个段的,实际物理内存希望分页,这怎么实现的呢?操作系统将段和页真的揉合到了一起,提出了虚拟内存这个概念(虚拟内存放在硬盘中)!虚拟内存根据寻址空间分配好了段,程序员写的代码放在虚拟内存分配的空间上,这样程序员也感觉内存变大了,并且程序从此不再受尺寸的限制,当程序执行的时候,虚拟内存在分好页进入到实际的物理内存当中去。当缺页的时候就产生一个中断去找页,在虚拟内存找到了页换入到内存中去。内存空间有限当还需要换入页面的时候需要把不用的页面换出,换出页面有三个算法,第一个是FIFO,先进先出,效果不好。第二个是MIN算法,这个性能是最好的,但是我们谁也不知道未来会发生什么,这个也不适用。第三个就是LRU算法,最近最长一段时间没有使用的页淘汰,LRU算法自己也可以试试去写一下,并不难Leetcode126 LRU

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值