考研408《操作系统》复习笔记,第三章《3.1 内存管理基本概念》

(计算机组成原理基础回忆)1)存储单元大小

  • 如果是【按字节编址】:就是一个存储单元大小是【1字节】=【8位(8 bit)】
  • 如果是【按字编址】:就是一个存储单元大小是【1个字】=【具体一个字多大取决不同的计算机(比如下图例子:一个字16位)】

2)存储单位换算

  • 【计算机组成原理】和【操作系统】的关于【存储】的单位换算都是按:
    • 【2的10次方】、【2的20次方】、【2的30次方】来换算
  • 【计算机网络】的关于【速度】的单位换算都是按:
    • 【10的3次方】、【10的6次方】、【10的9次方】来换算

一、【装入】和【链接】(理解即可)

1、【程序装入】基本概念

人话:就是各个进程运行时,他们的数据都是从外存放到内存的,因为进程的独立性,他们的数据需要装入到内存里各自不同的地方

基本过程分为3步:

1)【编译】

  • 人话:把程序员写好的代码、数据,"翻译成" 计算机看得懂的语言文件
  • 其中计算机组成原理里讲过【编译过程】,可以回顾一下(预处理、编译、汇编)

2)【链接】

  • 人话:把刚刚编译的几个分离的文件,合成一整块【模块】(类比快递打包)

3)【装入】

  • 人话:把这【模块】通过【装入程序】放到内存空闲区域,就可以供进程运行使用

【整个过程总结】:

2、【逻辑地址】和【物理地址】概念

前面我们已经了解了一个进程所需要的代码、数据是怎么装入到内存的一整个过程,现在我们的重点是研究:

  • 【进程所需的这些数据、代码】应该【放到内存什么位置?
  • 【进程】去内存【取数据、代码】的时候怎么知道他要的数据、代码**【到底在内存哪里?】**
  • 【逻辑地址】:
    • 进程还未存入内存的实际地址前,它所需的数据要存放在**【自己的进程装入模块哪个位置】**
  • 【实际地址】:
    • 进程所需数据模块已经存到内存了,进程去**【内存里实际要找到的地址】** 逻辑地址就像:你的大衣挂在自己宿舍储物柜里的下层,睡衣内衣和杂物放在储物柜上层;实际地址就像:你的大衣实际在6栋宿舍302里靠阳台的3号柜子里的下层。

3、三种装入策略

1)静态绝对装入

人话:提前定死了【逻辑地址】=【实际地址】

2)重定位装入(逻辑地址≠实际地址,二者有映射关系)

这里注意区分【静态重定位】和【动态重定位】的重点

  • 【静态重定位】:
    • 【逻辑地址 转化成 实际地址】发生的时机是在**【装入内存时(即程序运行之前)】**完成
  • 【动态重定位】:
    • 【逻辑地址 转化成 实际地址】发生的时机是在**【程序动态运行时】动态进行**
【静态地址重定位】(又叫【可重入定位】)

重点:【逻辑地址 转化成 实际地址】只能在**【装入内存时(即程序运行之前)】**完成,只有这么一次转换,后续不再变

  • 【关于 "进程对换、移动" 的概念】
    • 由于进程挂起、进程终止等原因,进程不会一直呆在内存
    • 而【可重入定位】中,进程的地址在装入时已经一次性定死了,一旦它发生对换后,内存里个地址空间一旦发生变化,他原先的地址就作废了,当它【调出 ---> 再调入】后就不能再进内存了因此说**【没有对换功能的内存管理方式】可以用【静待地址重定位】**
【动态地址重定位】

重点:【逻辑地址 转化成 实际地址】可以在**【程序动态运行时】动态进行**

  • 注意,这里涉及到【2个硬件】和【1个软件】:

    • 【硬件】:【重定位寄存器】、【地址变换机构】
      • 那么**【物理地址】=【逻辑地址】+【重定位寄存器值】**
    • 【软件】:【可重定位装入程序】
  • 这里涉及到一个【内存紧缩】知识点,先简单提一下:

    • 当进程从内存和外存之间移出移进的过程中,内存会留出很多间隙,也叫【空洞】
    • 如果不让进程紧挨着留出空位的话,虽然有很多空闲地方,因为这些空闲空间不是连续的,就没办法给新进程装入。
      • 因此通过【内存紧缩】技术,可以让各个进程在内存中移动、靠近,从而留出大量【连续的空闲空间】来给新进程装入
      • 而进程移动也必然会导致【实际地址改变】,因此需要依靠【动态地址重定位】,让程序在运行中也能够随时变换地址空间(就像吃席,坐的间距太大就不够很多人坐得下,要大家靠近一点才有空位给新人坐进来)

【总结】

【例题】

4、三种链接策略

【静态链接】

【装入时动态链接】

【运行时动态链接】

【例题】

【分段后面会学到,先记着】

分段就是把进程分成【空间大小各不一样】的段,每个段有不同的功能和权限

有时候一个程序里总有一些代码暂时用不上,就可以通过分段识别是哪些段暂时不用,先不链接,等要用时再动态链接到内存

二、内存保护

1、设置【上限寄存器】、【下限寄存器】

属于:静态重定位 + 内存保护

  • 存放内容:物理地址(实际内存地址)
    • 下限寄存器(基址寄存器) :进程起始物理地址
    • 上限寄存器 :进程结束物理地址
  • 工作方式(静态): 程序装入内存时就确定好物理实际位置,运行中地址不再改变。 CPU取逻辑地址后:【物理起始地址 = 逻辑地址 + 下限寄存器(基址寄存器))

2、设置【重定位寄存器】、【界地址寄存器】

属于:动态重定位 + 内存保护

  • 存放内容:实际物理地址 + 逻辑地址
    • 重定位寄存器(基址寄存器) :存放进程当前所在内存的起始物理地址
    • 界限寄存器 :存放进程的逻辑地址空间大小(最大逻辑地址)

工作方式(动态重定位流程):

  1. 程序内部用逻辑地址运行(编译 / 链接出来的地址不变)
  2. 运行时动态计算物理地址:【物理起始地址 = 逻辑地址 + 重定位寄存器(基址寄存器)】
  3. 越界检查:逻辑地址 < 界限寄存器值,否则报错。

【例题】

三、进程的内存映像

前面学进程时学过,进程映像就是进程运行过程中的一个【快照】,粗略的理解是【PCS + 代码段 + 程序段】

但是实际上我们要研究【进程在内存中的映像 】,也就是**【一个进程运行时在内存里会存储、用到哪些数据/代码】**

特别注意:

  • 1、注意【scanf】和【printf】函数是【输入、输出】函数,会触发【I/O中断】
    • 另外注意:【触发I/O中断时(阻塞态)】和【执行I/O时(运行态)】两个时机的区别
  • 2、区分【指针变量】、【"指针变量"所指向的 "实际数据"】和【malloc函数本身】的区别
    • 【指针变量】:如果是函数外全局变量就是【可读写数据】、如果是函数内局部变量就是【数据栈段(用户栈段)】
    • 【"指针变量"所指向的 "实际数据"】:是真正存放于malloc函数帮他们分配的空间,也就是【数据堆段】
    • 【malloc函数本身】:只是一个库函数,在【共享库映射区】

【例题】

1、这个例题在2.1进程章节的课后题第22题做过,各位可以回去看看