Linux-内存管理

本文最后更新于:几秒前

Learning OS is like reading books, you can communicate with top researchers.

In this blog, I will try to describe the knowledge in a time-line way.

Time 1 (万物初生)

新生的计算机并没有存储器抽象,彼时的程序直接对真实的物理内存进行操作。

example

mov Reg1, 1000

就是对物理地址为1000的数据进行操作。

对于这样的一个raw计算机是不可能实现并行程序的,因为此时每个程序都直接对物理内存进行操作,二者之间没有隔离。很容易出现二者对同一个地址的操作。

但通过硬件的帮助,我们可以实现一个很拙劣的可以运行多道程序的计算机。

使用 保护位与静态重定位 将程序连续地装载到内存中

即对内存分块,每块分配一个4bit的保护键,保护键存储在CPU的特殊寄存器中。PSW(程序状态字)中也有一个4bit码,若进程访问内存的保护键与PSW中的码不同,则会停止访问。

此时,本以为大功告成,程序间已经被隔离了,就开始多程序同时运行,但却出现了问题。

考虑下面的情况。

当程序被连续装载时,他们实际在的物理地址与汇编代码使用的物理地址是不同的(都认为是自己独占内存,从0地址开始)。

当执行图中两个程序的JMP指令时,下方的JMP指令会被正确执行,而上方的JMP却会跳到错误的地方。

So, 彼时的人们提出了静态重定位的技术,即当程序被装载到一个地址上时,该地址会被加到每一个程序地址上。

Time 2 (呼之欲出)

地址空间的提出

在第一时代,我们在使用静态重定位时就萌生了一个想法:能否让每个程序都有自己的一套地址呢?

起初只能直接对物理地址进行操作,也正是因为此导致多程序同时运行变得困难。

而且随着Computer的普及,一些”别有用心”的人出现了,他们可以通过程序轻易地控制操作系统。

这样的变化催促着一种变革,催促着对系统保护与重定位实现新的跨越,结合操作系统是对计算机底层内容的一个优美抽象,我们又能否将复杂的物理地址抽象成一个简单的形式呢?

地址空间的概念呼之欲出

地址空间是一个进程可用于寻址内存的地址集合,每个进程都有一个自己的地址空间,且不同进程间的地址空间(一般情况下)是相互独立的。

地址空间的简单实现:动态重定位

此时新添加了两个硬件设备:基址寄存器、界限寄存器

基址寄存器:存储程序的起始物理地址。

界限寄存器:存储程序的长度。

每当进程访问内存时,CPU都会把地址发送到内存总线上,自动把基址寄存器值加到地址上并且与界限寄存器进行比较。

这种实现方法虽然简单,但还是有些不足:

1.程序仍然要求连续装入内存。

2.比较运算可以很快,但加法运算由于进位传递时间的问题,在没有特殊硬件加持的情况下会显得很慢。

解决内存超载

虽然我们有了地址空间,可以简单地实现多程序并行,但这也提出了一个新的问题:

当全部程序的总的大小>内存大小时,怎么办?

最简单的策略就是:Swapping 技术

即让一个进程完整调入内存,运行一段时间后再存回disk。空闲的进程主要存储在磁盘上,不会占用内存。

但会在内存中产生holes,在一定时间需要进行内存紧缩。

另外一个很重要的问题,即对一个换入内存的进程应该分配多大的内存?

需要对数据段和堆栈段的增长有所考虑

空闲内存管理

Swapping技术的基础要求我们 必须充分了解当前的内存状态。

两种管理方法:

1. bitmap(位图)法

即将内存划分为一些大小固定的分配单元,每一个分配单元对应bitmap中的1bit,用0表示空闲/1表示占用。可以看到,bitmap的大小由内存和分配单元大小共同确定。

优点:实现简单且使用的空间大小固定。

缺点:每当要使用内存空间时,都要对bitmap搜索直到找出一个有k个连续的0的串(emmm,开销略大)

2.空闲区链表法


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!