一、CPU执行程序的基本过程

操作系统之内存管理(1)_用户区

前置知识:二进制相关

         利用二进制的特点设计出了一个译码器(3:8)译码器,8在计算机中很特别因为

8bit=1B  8位二进制构成一个字节,这是存储器存储的最小单位。由一个字节可以构成1K,1k能构成1M,1M能构成1G。原理就是8位二进制构成一个字节。

操作系统之内存管理(1)_逻辑地址_02

以少控制多的特点,通过选中输出线的原理,就能在CPU执行原理方面起到很好的作用。

1.解释CPU执行原理:

假设安装了4G大小的内存,有  2的32次方 个行,只需要用32根线就能选中这些行。所以地址总线只需要32位。进行编址0 到2的32次方-1地址范围。也就是CPU有32根线和内存卡相连接。CPU通过这32个地址线来对内存访问。选中内存地址后,通过数据线DB把内存地址数据传送到CPU寄存器保存中。数据进入CPU之后就可以进行对数据进行运算了。

2.CPU位数、OS位数、内存地址总线数字、内存数据总线、逻辑地址位数、物理地址位数、真实内存大小、物理内存大小

操作系统之内存管理(1)_用户区_03

(1) CPU的位数:现在基本都是32位或者64位,cpu的位数就是寄存器的位数,如果
    CPU内部寄存器是32位的就代表这是一个32位的cpu,64位同理。寄存器大小有
    什么影响呢?就是CPU一次运算的最大数据是32位二进制、64位同理。寄存器位
    数越大,能处理数据的宽度越大。总之CPU位数就是CPU内部寄存器的位数。
(2) OS(操作系统)位数:操作系统位数会受到CPU位数的限制,32的CPU只能安装32
    位的操作系统,硬件会限制软件。64为的CPU可以安装32位的操作系统,也能安
    装64位的操作系统,是可以向下兼容的。这就是软件可以自定义的表现。
(3)数据总线,就是内存卡的8根线,就是8位。看是什么内存卡。8位数据总线一次只
   能传输8位,全部传输到CPU寄存器中。如果是32位寄存器,需要传4次,才能把寄
   存器装满。64位就是就是传8次。
(4)物理地址总线数:就是32位,CPU上就是32根地址线,就说物理地址总线数是32。
   它能限制可访问内存的大小,如果地址总线有32位,能访问的地址范围是0到这就
   是从硬件层面限制可访问内存大小。内存卡大小也能限制可访问内存大小。4G和8G
   内存卡支持的访问内存是不一样的。软件方面也能限制可访问内存大小的范围,软
   件上可以设置,我只使用16根地址线进行寻址。
(5)逻辑地址的位数:简单来说逻辑地址位数等于操作系统的位数,每个操作系统位数
   确定了他都有操作系统支持的最大程序。逻辑地址的位数通常是支持最大程序运行
   的位数。他和OS位数概念基本等价,这都是在软件上所考虑的。
(6)虚拟内存理论大小和逻辑地址位数等价

二、内存管理逻辑图

操作系统之内存管理(1)_用户区_04

(1)从上往下看首先是编译和链接。为什么讲编译和链接呢?讲内存管理的时候其实都
   是在讲,内存是如何分块的、哪些块里装什么软件。就是说QQ这个软件到底装在内
   存中的什么地方。但是为什么还学编译、链接呢?原因是这样的,这个QQ程序被安
   装到磁盘上了,这个QQ程序怎么来的,通过在程序员编程过来的,通过编译和链接
   就是想告诉大家:
   
   一个安装软件,就是在网上下载的一个安装软件是怎么样通过程序员编码之后,通
   过编译和链接得来的。就是开发出来的QQ程序,就是讲的开发人员如何把QQ程序给
   开发出来的。通过编译链接得出来最终形成一个安装软件之后,这个安装软件就被
   安装在磁盘中了。安装在磁盘上之后:
	比如QQ安装在磁盘上之后,要运行程序的话,就要通过中间的装入这一步。现在已
   经得到了安装软件并且安装在了磁盘上面,这个时候需要把磁盘上的软件程序给复
   制到内存中。把程序从磁盘上装入到内存中,只有装入到内存之后,整个程序才能
   被运行。
(2)装入会引出两个问题:第一个怎么把程序装入到内存中?第二个问题把程序装在内
   存哪里?整个第三章都在叙述程序装在哪里。装在哪里就会引出两个小的问题:
   第一个是记录,怎么记录起来呢?通常是用一个表格来记录,在后面讲很多的装入
   方式的时候。
	
   绝对装入、静态重定位装入、动态重定位装入,这三个方法就解决了程序怎么内存
   装入的问题。每一种方式都是不一样的都有他们各自的特点。
	这些程序被装入到内存卡中的什么地方呢?用了5种方式告诉你装入到内存的什么
   地方。你把一个东西放在内存中的某一个地方,放在一个什么样的地方你不可能说
   靠脑子记住,肯定会做一个笔记,在操作系统中用了一个表格来把某一个程序被装
   在了什么地方给记录起来,记录起来有什么作用呢?是方便查询的。通过查询表格
   就能知道程序装在内存的什么地方了。CPU就可以开始执行程序了。
	
   因此整个第三章就是在说装入程序的一些相关知识,在装入过程中,最主要关心的
   就是怎么样装入,有三种方式。装在内存的哪里呢?有5种方式解释。这就是两大
   问题。要对第二个问题装在哪里进行记录,便于操作系统查询。每一种方式下都有
   一个表格来记录,几录好之后对于每一种表格都有一种方法来查询。

三、编译、链接

操作系统之内存管理(1)_逻辑地址_05

(1)在a.c 源程序文件中有一段代码C=A+B。在b.c源程序文件中有一段代码W=X-Y。
   在编译的过程中他们做了哪些工作呢?将C语言编译成一种汇编指令,每一条汇编
   指令都对应一段机器代码。在a.o文件中全是010101的代码,但是在这里用汇编语
   言代码代替所有的0101.
	编译过程中先把C语言编译成汇编语言,汇编语言在进一步的转换为机器语言。所以
   在编译的过程中会产生汇编语言,咱们就以汇编语言来理解编译过程中到底做了什么
   事情。
   很简单的一段C代码执行过后,就变成了好几行汇编代码,才能实现C=A+B。
(2)描述编译的过程:
   LOAD 1 6:1代表R1寄存器,6的意思是说,第6行的A。它要将内存的第6行A加载
   到R1寄存器中。也就是R1存在了A这个值。ADD 1,8:它的意思就是说,把第8行
   的一个变量与R1寄存器相加。现在R1寄存器中是A,也就是把A+B赋值到了R1寄存
   器中。此时R1中就保存A+B了,然后STORE 1,10. 在将R1寄存器存到内存中的第
   10行,第十行是C。也就是在将A+B这样的一个计算结果赋值给C。这样的一个多条
   指令集合,就实现了C=A+B的计算。这就是编译之后形成的一个汇编代码。
	编译的时候会为每个模块产生一个从0开始的逻辑地址,汇编语言的地址参数,也与
   逻辑地址有关。逻辑地址是一个软件上的概念,b.c文件也是这样产生的。这是编译
   阶段的一个过程。从C文件到了一个汇编的文件.o文件
	
   编译完之后还要链接起来,因为两个模块之间他们可能会连在一起,比如说a.c和
   b.c都是在一个工程项目中的,这两个文件合并在一起才能形成一个软件。这个软
   件中有加法模块和减法模块。加法模块编译出来有它自己的逻辑地址,减法模块编
   译出来也有他自己的逻辑地址。现在要让他们合并在一起这个软件就有了加法和减
   法的功能。于是就需要对这两个模块进行链接在一起。链接在一起之后,这两个模
   块的逻辑地址会自动修改,会重新对模块的逻辑地址进行修改。
   
   将两个模块合并在一起之后进行了重新的编码,将模块指令设计到的地址都会进行
   修改。
   这就是编译和链接所做的工作:
   首先是编译,将每一个C语言的.c文件,将源代码编译成汇编代码或者是机器代码,
   每一个模块都有一个从0开始的逻辑地址。所有的模块都有自己的地址,并且指令
   中设计到的地址与编码的逻辑地址有关,这就是在编译过程中所需要了解的。
	编译之后各个模块需要链接合并成一个模块,在合并过程中,进行统一编址。模块
   合并后会形成一个统一的逻辑地址。这个逻辑 地址也是从0开始编码。这就是链接
   做所的事。编译、链接之后就会形成可执行文件.exe。这个文件就已经被存放在了
   磁盘中,下一步就研究怎么装入到内存中。

四、装入介绍

操作系统之内存管理(1)_寄存器_06

(1)这是一个磁盘和内存卡的示意图,其中磁盘中安装好了一个软件,这个软件假设
   是QQ软件的一部分,它执行的代码是C=A+B。通过编译、链接之后形成了一种可
   执行文件,这个可执行文件就保存在磁盘上了。
	保存在磁盘上之后,程序要运行起来。就需要把这个可执行文件拷贝到内存卡中,
   因此把C=A+B拷贝到内存卡中,内容是一样的。复制进去到内存卡中就能完成执行
   C=A+B,想的很好但是,和实际是不一样的。是不能完成C=A+B这段功能的。
   为什么?
	因为讲了每一个程序,在编译、链接之后生成的一个程序,他们中参数的逻辑地址
   都是相对于自己的程序而言的,这样的一个地址就会引发一个问题?只从自己的程
   序中开始编址和内存中的地址没有对应起来。
	整个计算机中只有一个内存卡,因此对于CPU来说,内存卡是唯一的,CPU会对内存
   卡进行一个编址,会生成一个地址范围。但是对于程序员编写的程序而言,是按照
   自己程序的地址进行编址生成范围的。CPU只认自己对内存卡的编址,这样就发生与
   程序员程序地址冲突和错位导致程序不能正常执行。
	
   结论就是,如果随意的给内存装入程序,CPU可能无法正确的运行每一条程序或指令

(2)为了解决这个问题,就有了三种解决方案:绝对装入、静态重定位装入、
	动态重定位装入。

1.绝对装入

定义:装入前,就确定好程序装入的位置,使得程序的逻辑和内存的地址之间进行对齐
    不会产生一个错位的情况。这样CPU就能正确的取指令了。事先在编译和链接得时
    候就确定好,这个程序要装在内存的什么地方。

2.静态重定位装入

定义: 在装入时,由装入程序,(装入程序是操作系统的一部分)对逻辑地址进行一次
     性修改,从而来达到避免地址错位。保证CPU正确运行程序。
	
  	编译、链接之后形成的文件依然是,程序地址依然是自己程序的内部编址,在拷贝
    程序的可执行文件进入到内存中运行时,由操作系统的装入程序,一边拷贝程序
    
    一边修改进入到内存程序的地址。在装入的同时,就一直在修改程序的逻辑地址进
    入内存。
	比如,在分配内存时,要将所运行的程序装入到在内存中地址1000H开始的位置,
    在程序从磁盘拷贝到内存的时候,一边装入,也一边修改程序的逻辑地址和这个
    内存地址对应。因此,这样边装入边修改,也可以避免地址错位。
(2)怎么理解重定位呢?
	第一次程序在运行时,把程序装入到了内存中1000H地址的位置,第二次在运行是,
	也可以把程序装在内存地址为500H开始的位置。进行运行。重定位就是同一程序在
    内存中运行时,每次装入到内存中的地址可以不一样。原因就是由操作系统的装入
    程序边装入,边修改程序。
(3)怎么理解静态呢?
	比如就是今天指定好了这个程序装入内存地址的位置为1000H,装入好之后,这个
    程序就不能在移动了,只能固定在这个地址位置。如果想让程序上移500H,只能关
    闭程序,然后再重新加载程序。修改到500H。必须通过结束程序,在重新装入内存
    才能修改地址位置。
    绝对装入内存位置固定,程序装入了就不能改变了,即使重新加载也不会改变。
    但是静态重定位,可以改变第二次程序装入在内存中的位置。重新加载程序后,
    就能改变位置。

3.动态重定位装入

(1)动态重定位定义:程序运行时,动态重定位是在程序运行时,才开始的起作用的。
   利用CPU内部的重定位寄存器,让CPU认为程序的逻辑地址和内存物理地址是对齐的
	 我们来看一下这个重定位寄存器是怎么样起的弥补的作用:
   首先磁盘上保存着一个源程序,编码逻辑地址是从0地址开始的,假设他会装在内存
   中1000地址的位置。他们之间差了1000。
	操作系统把一段程序拷贝到内存的时候,在第二章讲过,拷贝之后需要为每一个程序
   建立一个PCB保存信息。PCB就交代了该程序拷贝到了内存的什么地方,
   比如是1000H,操作系统读到这个程序的时候,会把这个信息填写到重定位寄存器中
   CPU执行这段程序时,会进行弥补的作用,把0+1000,正好能把地址修改好。通过
  重定位的加法,弥补了,可以对地址进行对齐。这段程序的逻辑地址并没有真正修改的
	怎么理解动态呢?
  
  程序在内存中进行移动是可以的,就只要把PCB中的1000H改成所需要的位置就可以。
  接下来就可以运行了。因此有了重定位寄存器之后,想要对程序在内存中移动,只需
  要修改该程序的PCB入口地址就可以了。

区别:
	动态重定位不需要结束程序,就可以修改程序在内存中的地址
	静态重定位想在内存中修改程序地址,必须先结束本次程序,在重新从磁盘读入内存
  才能修改在内存中程序的地址位置。

五、内存保护

操作系统之内存管理(1)_寄存器_07

(1)操作系统必须要在内存管理中实现内存保护的功能。为什么?
   内存保护又叫越界保护。再讲进程间通信的时候,讲过由于进程之间是相互独立的
   他们之间分配的内存是相互独立的,因此需要进程间通信,进程间相互独立的意思
   就是说A进程与B进程都有他们自己独立的内存空间。如果不对内存加以保护,进程
   间任意访问会对安全性造成影响。A进程是木马,B进程是正常程序。如何任意访问
   就造成了木马程序直接对别的进程造成破坏。窃取信息。
	内存保护是通过硬件加操作系统一起实现的,独立空间、互不影响。通过进程保护
   每个进程通信时,只会接收自己认为安全的信息。这样能有效的屏蔽木马程序。
	通过应该实现的,用上下限寄存器,和重定位寄存器加现长器寄存器。

六、内存分配

1.单一连续分配

单一连续分配是什么意思:这是一个内存卡,内存卡被划分成了两个部分,系统区和
	用户区。系统区中安装的是操作系统,用户区装的应用软件。
	在使用时,只会在用户区装一个程序运行,必须等内存中程序运行完之后,才能装
  第二个程序。在单一连续分配中,用户区里只装单个程序。
	连续是什么意思呢?程序从磁盘复制到内存中所分配的地址的连续的。除了操作系
  统之外只运行一个程序

特点:
		1.单用户、单任务  
    2.内存利用率极低(因为有内部碎片)
		  怎么理解内部碎片呢?整个用户区被QQ程序所占用,虽然QQ占据了整个用户区
      但是只使用了用户区的一部分。所以剩下的空间就叫碎片。这样的碎片是属于
      QQ程序内部的碎片,
			所以就叫内部碎片。
			碎片:没有利用起来的内存空间
			内部:虽然内存空间属于某个程序,但是该程序没有使用到这段空间。
	  3.单一连续分配通常采用绝对装入的方式

2.固定分区分配

它是为了克服单一连续分配中内存一次只能装入一个程序的缺点而出现的。

(1)固定分区分配是怎么样装多道程序的;仍然是有一个内存卡,把操作系统装在了
   系统区,剩下的空间称为用户区,在用户区中每种操作系统都是不同呢,假设在
   一个内存大小为64MB的空间,操作系统的系统去占用了16MB,用户区剩下了48MB
   
   假设这个操作系统划分了6个小块每个分区有8MB,其中每个分区只能装一道程序。
   所以这个内存中只能装入6个程序在里面。这个分区可以通过程序员手动修改,变成
   更多或者更少的分区。这是等分的分法。不等分也行 2 4 8这样分区。如果小的程
   序多,就多划分小分区。大程序就多划分大分区。
(2)特点:
   ①在一个分区中,不论大小只能装入一道程序②分区的大小都是很讲究的,太小装程序
   装不进去,分区太大内存利用率会降低③会产生内部碎片。
	在固定分区分配中,在装多道程序的时候,需要用一个分区说明表,来记录分区有多
   大,在什么位置、分区的状态既有没有被装载程序。都需要去记录。
(3)分区说明表在操作系统被加载到内存区的时候,就已经被建立了,第一个是分区号
   区块大小 起始位置 状态。
(4)所以在理解固定分区分配的时候,要理解这三个层面:1大小相等的分区和大小不
   等的分区有什么特点、2理解固定分的三个特点、3理解为什么要使用分区说明表	
	固定分区分配一般采用静态重定位装入.

3.动态分区分配

(1)动态分区分配也是为了完成多进程的功能,但是他和固定分区一样都是为了完成多
   个进程的分配方法。为什么要提出动态分区分配呢?开始在固定分区分配的第二个
   特点讲过讲过分区的大小都是很讲究的。太大装不进内存,太小浪费内存。因为固
   定分区,都把分区大小固定好了,这样的规划,不知道能不能适应接下里的程序大
   小的安排。所以不太灵活。于是就有了动态分区分配来解决,固定分区分配,分区
   大小很讲究的难点。为什么难?因为不能知道以后会装多大的程序。
(2)接下来看动态分区分配是,怎么解决大小很讲究的这样的一个难点的。现在来直接
   讲一个过程来体会,动态分区是怎么分的。
	首先第一步,操作系统安装在系统区16MB,剩余的48MB为用户区。如果有一个进程
   A大小为16MB。用户区会给他分配16MB。用48MB-16MB=32MB所以用户区还有32MB
   是空闲的。动态分区分配的意思就是,程序进来之后要多大的空间,就给分配多大的
   空间。进程B要8MB,也会直接给分配8MB给进程B。进程C要20MB,会继续给他分配
   最后内存中的用户区剩余了2MB。此时进程D有6MB大小,但是空闲的分区只有2MB。
   这时候进程D就需要等待其他进程退出。有了空间,才继续给进程D分配。剩下的空间
   会越来越小。
	相邻的空闲小分区,会合并成一个大分区。但是现实情况是,随着进程的不断执行,
   会存在越来越多的小分区不能被利用。这些不能被利用的起来的小分区就叫做外部
   碎片
   
	为什么称为外部碎片?
   因为这些内存中的小分区,不属于任何一个进程,是永远利用不起来的。称为外部
   碎片 .
	当外部碎片越来越多的时候,需要出现一种紧凑技术

	看这个图,利用紧凑技术可以把,2MB 下移和20MB空间换位置,这样以后,
   2个2MB的空间可以形成一个4MB的空闲空间。它的硬件支持是动态重定位寄存器。
(3)既然是动态分区分配,肯定会存在一个分区说明表,此时的分区说明表和固定分区
   是不一样的,固定分区的说明表是,一旦运行起来分区就固定了。但是动态分区就
   不一样了。
	
   每个分区有多大,分区有多少个都是不确定的,都是随着进程进出内存而动态变化
   

4.动态分区分配算法

操作系统之内存管理(1)_寄存器_08

现在分区表、如上图所示,空闲的分区只有,7MB、10MB、6MB。现在有一个大小
	为5MB的D程序。它应该装在上面3个空间中的那个空间里呢?因为 7 10 6 都能装
	下大小为5MB的进程。怎么选呢?
  
 (5)有4种选取的方法:
	a.首次适应算法:他就是按照地址递增的顺序来对空闲分区排序,地址从低到高
      第一位是7MB 第二位是10MB、第三位是5MB。操作系统每次都是从低地址向高
      地址开始扫描,扫描到第一个空闲分区的时候,就把D程序装入到7MB的空间。
      所以叫首次适应算法。
	
    b.最佳适应算法: 最佳的意思就是找一个尽可能不浪费的空间的分区来装入进程
      7 10 6 中显然装5MB 肯定是6MB空间最合适,因为分配6MB空间,装5MB的进
      程只会剩下1MB的空间。最佳适应算法就是选取一个最接近进程大小的空间分配
	c.最坏适应算法:找最大的空间给进程分配,从最大的空闲块开始分配
	d.临近适应算法:	 从上一次分配空间的位置继续进行分配、假设在内存分配时
      已经分配到7MB这个分区的位置,之间从7MB这个位置开始查询分配。7MB位置使
      用完,就之间在7MB空间后面继续查询分配。
临近的意思就是,接着上次分配的位置继续查询,而a、b、c这三种都是从头扫描到尾

依次的去扫描。低地址到高地址
首次适应算法就是低地址到高地址扫描到第一块能用的就直接分配。
最佳适应算法就是从头到尾扫描,找一个最合适的空间分配
最坏适应算法也是从头到尾开始扫描,找一个最大的空间分配
临近适应算法就是第一次开始扫描分配之后,第二次扫描在第一次扫描结束的位置开始。