操作系统

内存管理

x86-32硬件-内存架构

  1、地址是访问内存空间的索引。
  2、80386是32位机器,即可寻址的范围是2^32=4G字节。
  3、物理内存空间是计算机提交到总线上的用于访问计算机上的内存和外设的最终地址。一个计算机中只有一个物理地址空间。
  4、线性地址空间是在操作系统的虚拟内存管理下,每个运行的应用程序能访问的地址空间。每个运行的程序都认为自己独享整个计算机系统的地址空间,这样可以让多个运行的应用程序之间相互隔离。
  5、逻辑地址空间是应用程序直接使用的地址空间。

内存使用与分段

  1、重定位:修改程序中的地址(是相对地址)。
  2、编译时重定位的程序只能放在内存固定位置,载入时重定位的程序一旦载入内存就不能动了。因此重定位最适合的时机是运行时重定位,即在运行每条指令时才完成重定位。(每执行一条指令都要从逻辑地址算出物理地址)每个进程有各自的基地址,在每条指令执行的第一步先从PCB中取出这个基地址。
  3、内存如何使用?首先找一块空地址,得到基地址,然后将基地址写入PCB寄存器中,在程序运行中,每执行一条指令,首先从PCB中取出基地址,再加上程序中的逻辑地址,即可翻译成物理地址,这样内存就使用起来了。当进程间切换时,PCB中的值也会跟着变化。   

分段和分页机制

  1、分段和分页是两种不同的地址变换机制,它们都对整个地址变换操作提供独立的处理阶段。尽管两种机制都使用存储在内存中的变换表,但所用的表结构不同。实际上,段表存储在线性地址空间,而页表存储在物理地址空间。因而段变换表可由分页机制重新定位而无需段机制的信息或合作。段变换机制把虚拟地址(逻辑地址)变换成线性地址,并且在线性地址中访问自己的表,但是并不知晓分页机制把这些线性地址转换到物理地址的过程。类似地,分页机制也不知道程序产生地址的虚拟地址空间。分页机制只是简单地把线性地址转换成物理地址,并且在物理内存中访问自己的转换表。

CPU管理

  

进程

  1、进程就是一个程序的执行过程。
  2、只有进程从内核态转移到用户态时,才可能发生抢占,进程在内核态下运行是不会被抢占的。
  3、多线程是指操作系统在单个进程内支持多个并发执行路径的能力。
  4、进程中所有线程共享该进程的状态和资源,它们驻留在同一块地址空间中,并且可以访问到相同的数据。当一个线程改变了内存中的一个数据项时,其他线程在访问该数据项时能看到变化后的结果。
  5、在大多数操作系统中,独立进程间的通信通常需要内核的介入,以提供保护和通信所需要的机制。但是由于在同一个进程中的线程共享内存和文件,它们无需调用内核就可以通信。
  6、进程的终止会导致进程中所有线程的终止。
  7、进程从创建(Linux下调用fork())到结束的整个过程就是进程的生命期,进程在其生命期中的运行轨迹实际上就表现为进程状态的多次切换,如进程创建以后会成为就绪态;当该进程被调度以后会切换到运行态;在运行的过程中如果启动了一个文件读写操作,操作系统会将该进程切换到阻塞态(等待态)从而让出CPU;当文件读写完毕以后,操作系统会在将其切换成就绪态,等待进程调度算法来调度该进程执行……
  8、用户态到内核态只能通过中断的方式。

进程同步与死锁

  1、临界区:一次只允许一个进程进入该进程修改其信号量的那一段代码。
  2、临界区代码保护原则:互斥进入,即如果一个进程在临界区中执行,则其他进程不允许进入。
  3、好的临界区保护原则:(1)有空让进:当若干进程要求进入空闲临界区时,应尽快使一进程进入临界区。(2)有限等待:从进程发出进入请求到允许进入,不能无限等待。

线程

  1、线程保留了并发的优点,避免了进程切换代价。
  2、用户级线程,在用户态下切换。如果某个线程调用硬件在内核中发生阻塞,内核就会切换到其他进程,那么在之前那个进程下的用户级线程就会卡在那不动。
  3、用户级线程用了两个栈,而内核级线程用了两套栈。即用户级线程切换的时候,TCB切换,用户栈也跟着切换;内核级线程切换的时候,TCB切换,用户栈和内核栈都要跟着切换。
  4、内核级线程在内核栈之间切换的时候,通过TCB找到内核栈指针,然后通过ret切到某个内核程序,最后再用CS:PC切到用户程序。

系统调用

  1、在通常情况下,调用系统调用和调用一个普通的自定义函数在代码上并没有什么区别,但调用后发生的事情有很大不同。调用自定义函数是通过 call 指令直接跳转到该函数的地址,继续运行。而调用系统调用,是调用系统库中为该系统调用编写的一个接口函数,叫 API(Application Programming Interface)。API并不能完成系统调用的真正功能,它要做的是去调用真正的系统调用,过程是:把系统调用的编号存入EAX;把函数参数存入其它通用寄存器;触发 0x80 号中断(int 0x80),进入内核态,调用相关的内核函数。