计算机对于内存的使用:将程序放在内存中,PC指向开始地址,执行指令,过程如下:
1、 先找到程序的入口地址,读取磁盘上的程序,并找一段内存的空闲区域,将程序装进内存中。
2、 重定位,将程序中的逻辑地址和程序实际放在内存中的位置(进程的PCB中)相结合,得到程序在内存中的实际地址,并将其赋给PC指针(一个程序计数器,记录指令执行的地址)。(载入运行程序时执行重定位,如果在编译时重定位,那么程序只能存放在内存的固定位置)
3、 通过PC指针找到指令,执行指令。
在程序中操作系统并不会把程序整块载入内存,因为一个程序包含了许多数据结构,不能一概而论。例如程序的代码是只读的,相对固定的;而数据是会随着程序的运行动态变化的
图一:内存分段原因
所以在在内存把程序载入内存中时,会采用分段的方式进行加载,不同的程序段使用不同的存储形式,简单的说就是对于不同的程序块,留不同的空闲空间,分开访问。例如代码段一般是只读的不会增长,那么就不留空闲空间。而动态数组段就留一个较多的空闲空间,因为需要动态增长。如果不采用分段,那么当动态数组不断增长,超过了原来分配的空间,那么就必须把整个程序拷贝到另一个更大的空间。这个无疑是浪费空间和时间的,如果仅仅是把动态函数的那段移动到更大的空间,这样效率会有很大的提高,并且使内存的管理更加精确。那么定位具体的指令(数据)的地址就可以修改为:<段号,段内偏移>。例子如图:
图二:分段的实现原理
在操作系统中有两个表GDT(也是一张二维表,只是记录的信息与LDT略有不同)表和LDT表,GDT表存储在操作系统程序中,LDT表存储在运行在操作系统中的PCB中;GDT表存储了操作系统的进程段表,并且存储了指向LDT表的指针,LDT表就只存储了本进程的进程段表。
图三
每段在内存中的分配(动态分配)
对于内存管理,操作系统需要维护两张表,一张是空闲分区表,一张是已分配分区表,具体示例如图:
图四
对于分区的分配过程较为简单,在此我就以一组图例进行展示:
图五
图六
关于新申请空间的分配问题:
当提出段申请的时候,例如对于图六,需要申请一个40K的段,那么就有3中分配方式。
1、 首先适配:直接顺序查询空闲分配表,只要装得下,就分配一块。
2、 最佳适配:就是遍历表,找到比需要空间大或者相等的,且两者大小最接近的空闲空间,但是这种方式会留下极小的空间,不便处理。
3、 最差适配:查询空间表,找到最大的空闲空间,然后分配一块出来。
当然,这种分配方式是有问题的,就是必须找一个>=目标区域的空间,但是这样分配的空间就难免出现一些内存空间没法使用,导致浪费;一种解决方法是定期把使用过的空间挪到一堆,把空着的空间集中到一起。当然这种方式有两个问题:1、挪到空间需要花费时间,在此期间计算机不能正常使用;2、把数据和代码挪到一起了,不利于数据段的动态增长。
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。