ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

操作系统(学习笔记)

2022-09-06 01:01:41  阅读:209  来源: 互联网

标签:操作系统 程序 笔记 学习 指令 内存 进程 页表


操作系统(学习笔记)

 

内存管理

重定位

让内存用起来:将程序放到内存中,让程序跑起来,PC指向开始地址,内存就用起来了;

地址重定位:编译时重定位(效率更高)、载入时重定位(灵活性好);

编译时重定位:程序只能放在内存固定位置;

载入时重定位:程序一旦载入,内存就不能动了;

重定位:可变的基准地址+不变的偏移地址;

程序载入后也要移动;

运行时重定位:程序换入时,进行重定位;

程序换入时,将新的基地址写入PCB,以便完成重定位;

程序不是常驻内存,而是将执行的程序换入内存,而将不执行的程序换出内存;

PCB的基址放入基址寄存器,和程序中的偏移地址相加计算重定位地址,然后再翻译成物理地址;

PCB→基址寄存器→偏移地址→重定位→物理地址;

分段

内存分段管理:每个段有各自的特点、用途;

代码段、数据段、堆栈段;

分段管理符合用户观点:可以独立考虑每个段(分治)

如何定位具体指令(数据)<断号,段内偏移>mov [es:bx],ax

操作系统也是一个进程,操作系统的描述符表,称为GDT=globle descriptor table;

每一个用户程序也是一个进程,也有各自的描述符表(段表),称为LDT=local descriptor table

堆栈段

 

1. 为函数内部的局部变量提供存储空间。

2. 进行函数调用时,存储“过程活动记录”。

3. 用作暂时存储区。如计算一个很长的算术表达式时,可以将部分计算结果压入堆栈。

数据段(静态存储区)

包括BSS段(Block Started by Symbol)的数据段。BSS段存储未初始化或初始化为0的全局变量、静态变量,具体体现为一个占位符,并不给该段的数据分配空间,只是记录数据所需空间的大小。数据段存储经过初始化的全局和静态变量。

代码段

又称为文本段。存储可执行文件的指令;也有可能包含一些只读的常数变量,例如字符串常量等。

  .rodata段:存放只读数据,比如printf语句中的格式字符串和开关语句的跳转表。也就是你所说的常量区。例如,全局作用域中的 const int ival = 10,ival存放在.rodata段;再如,函数局部作用域中的printf("Hello world %d\n", c);语句中的格式字符串"Hello world %d\n",也存放在.rodata段。

但是注意并不是所有的常量都是放在常量数据段的,其特殊情况如下:

1)有些立即数与指令编译在一起直接放在代码段。

2)对于字符串常量,编译器会去掉重复的常量,让程序的每个字符串常量只有一份。

内存分段(一个进程)

栈stack

由编译器自动分配、翻译。存放函数的参数值和局部变量值、操作方式类似于数据结构中的栈;

堆heap

由程序员分配、释放。如果程序员不释放,程序结束时有可能由操作系统释放。它和操作系统中的堆是两回事,操作方式类似于链表;

BSS

存放未初始化的全局变量和静态变量;

数据段data

存放初始化之后的全局变量和静态变量;

代码段code

程序代码主体,函数主体等。为二进制格式;

栈、堆辨析:

1、栈区(stack):由编译器自动分配释放 ,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区(heap):由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

项目

栈stack

堆heap

申请方式

系统自动分配

程序员分配,需指明大小

系统响应

只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出;

操作系统有一个记录空闲内存地址的链表,系统收到申请时,会遍历链表,找到第一个空间大于申请的堆结点;然后将该结点从空闲结点链表中删除,并将该结点分配给程序;

操作系统会在首地址处记录本次分配的大小,这样,代码中的delete语句才能正确释放内存;

由于找到的堆结点大小不一定正好等于申请大小,系统会将多余部分重新放入空闲列表;

申请大小

编译程序时,由编译器确定,是一个常数,Windows中一般为2M;因此在栈中获得的空间比较小;

系统用链表存储空闲内存地址,自然时不连续的,链表的遍历也是从低到高;堆的大小受限于计算机系统中有效的虚拟内存;

扩展方向

向低地址扩展

向高地址扩展

申请效率

系统自动分配,速度较快;程序员无法控制;

程序员分配内存,一般速度比较慢,而且容易产生内存碎片,不过用起来方便;

存储内容

函数调用时,第一个进栈的是下一条指令的地址,然后是函数参数;

大多数C编译器中,参数是从左到右入栈,然后函数中的局部变量入栈;

静态变量是不入栈的;

当函数调用结束,局部变量先出栈,然后是参数,最后 栈顶指针指向最快开始存的地址,也就是主函数中的吓一跳指令,程序由该点继续运行;

一般在堆的头部用一个字节存放堆的大小;

堆中具体内容由程序员安排;

GDT+LDT+偏移;

 

 

分页

内存如何分割:固定分区(等分)、可变分区(不等分);

以分配分区表,空闲分区表;需要多少,就割多少;

内存分配:首先适配(随机)最佳分配(挑最小的分配,产生细小空间),最差分配(挑最大的分配,分配比较均匀);

分页:解决内存分区导致的内存效率问题;

可变分区造成的问题:产生内存碎片;

解决:将空闲分区合并,需要移动一个段(复制内存)内存紧缩;

内存紧缩需要花费大量时间,不可取;

不产生面包碎屑;将面包切成片,将内存分成页;

将每个段内存请求,系统一页一页的分配给这个段;

内存需要分页,程序需要分段;最多浪费一页4k;

通过页表到内存中找;MMU内存管理单元,通过逻辑地址,寻找内存物理地址;

每个段都打散成很多段,相应的,内存也分割成很多页;

 

多级页表

为了提高内存空间利用率,页应该小,但是页小了,分的页就多了,页表就大了;

页表的作用:逻辑页(页号)→物理页(页框号)

页面尺寸通常4K,地址32位4G内存,有2^20个页面;

2^20个页表项都要存放在内存中,需要4M内存,系统并发10个进程,就需要40M内存;

实际上,很多逻辑地址根本不会用到;

将不使用的地址项从页表中删除,减小页表大小,减少内存浪费;

页表必须连续,否则要挨个查找,访问一次内存就要提前访问内存很多次,大大降低效率;

页表连续时,用页表起始页加上一个偏移量,就可以一次性查找到页表项;

既要连续,又要占用内存少;就要使用分级页表;

页目录+页表;每个页目录项对应1K个页表,需要4M内存;

多级页表,空间利用率好(节省内存),但需要增加访问次数,降低访问效率;

每增加一级,访问内存次数就要增加一次,但是内存占用会大大减少;

TLB快表,是一组相连快速存储,是一个寄存器;

记录正在使用的多个页表,再次访问时,可以一次直达对应地址;

快表相当于记住最近搜索项,或最近查找项;

快表+多级页表:节省内存、又很快;

TLB命中率有多少?要想TLB好使,命中率必须达到一定水平;

要想真正实现“近似访存1次”TLB命中应该很高;

TLB越大越好,但是TLB寄存器很贵,通常只有[64-1024];

程序地址访问存在局部性locality in space,就是说经常集中性访问一段内存;

TLB解决多级页表访问效率低的问题;

 

虚拟内存

程序分段(打散)→页表(虚拟内存)→物理地址;

虚拟内存实现了既支持分段又支持分页的内存视图;

段、页同时存在:段面向用户,页面向硬件;

虚拟内存将段和页紧密的结合在一起;

段号+偏移(CS:IP)→段表→段号+偏移→虚拟地址→页号+偏移→页表→物理页号+偏移

 

 

进程=正在进行的程序=执行中的程序

进程

程序的本质:数据和对数据的处理;

进程的本质:正在运行(执行/动态)的程序;

进程是操作系统进行资源化分配和调度的基本单位;

进程是应用程序关于某些数据集合上的一次运行活动;

进程是程序的一次执行过程;

进程是动态的,程序是动态的,执行的程序才是进程,没有执行的程序不是进程;

动态的程序才是进程,静态的程序不是进程;

每个进程拥有独立的地址空间;

进程之间的地址空间是隔离的;

一个进程崩溃不会影响另一个进程;一个进程崩溃不会影响操作系统;

地址空间包括代码段、数据段、堆栈段;

代码段:存储程序的代码;

数据段:存储程序的全局变量和动态分配的内存;

堆栈段:存储函数运行时的局部变量;

 

多进程

CPU计算速度和IO速度严重不匹配;5.7*10^5:1

导致CPU利用率很低;

多道程序,交替执行,可以大大提高CPU利用率;

一个CPU上交替执行多个程序:并发(同时出发,交替执行);

核心是如何在不同任务间进行切换;

而切换的核心就是中断技术;

切出去的时候要记录当前程序的执行状态,切回来的时候再读出当时的状态,以便接续执行;

进程:进行(执行)中的程序;

运行的程序和静态程序不一样。

需要描述这些不一样,都记录在PCB中;

PCB:process ctrl block(进程控制块),用来记录当前进程的当前状态;

在操作系统代码当中是一个结构体:struct task_struct{...}

Ø 进程有开始有结束,程序没有;

Ø 进程会走走停停,走停对程序没有意义;

Ø 进程需要记录ax、bx,程序不用;

多进程:多个程序交替执行,分别成为进行中的程序;

如何实现多进程图像:

1. 通过映射表实现内存的分离;

2. 读写PCB,OS中最重要的结构,贯穿始终;

3. 要操作寄存器完成切换;

4. 要写调度程序;

5. 要有进程同步和合作;

6. 要有地址映射(防止相互干扰);

 

进程=资源+指令执行序列;

线程:保留了并发的优点,避免了进程切换代价;

将资源和指令切换分开;

一个资源+多个指令执行序列;

线程:只切换指令,而不切换资源;

指令的切换的核心是Yield;

Create就是第一次切换时的样子;

用户级线程、内核级线程;

 

 

进程同步

同步:多个进程的推进合理有序;

进程之间的合作,合理有序的推荐,而不是任意向前推荐;

一个进程发出信号,另一个进程等到该信号,才能继续向下执行;

关键词:信号、合作、同步、等待、阻塞;

需要让进程走走停停,来保证多进程之间的合理有序;

分析走和停的实际,是多进程同步的关键;

n 同步并不是同时,而是交替执行;

n 交替执行不是随意的交替,而是合理的有序的交替;

程序可以有多个(多道),但是正在执行的程序只能有一个;

 

信号量

仅仅依靠一个counter信号,不足以支持进程的sleep和wakeup;

需要一个信息更加丰富的量,来记录信号;

通过信号量sem实现等待sleep与唤醒wakeup;

sem小于0,表示有进程在等待资源,生产者处于睡眠状态,唤醒;

信号量:1965年,由荷兰学者Dijkstra提出的一种特殊整形变量,用来sleep和wakeup;

semphore英 /ˈseməfɔː(r)/ 美 /ˈseməfɔːr/n. 信号标,信号量信号标信号对象

保护信号量:

竞争条件:race condition:和调度有关的共享数据语义错误;

错误由多个进程并发操作共享数据引起;

原子操作:一段代码只允许一个进程进入;

 

临界区:一次只允许一个进程进入的该进程的那一段代码;

找出临界区代码;

原子操作、互斥;

临界区代码保护原则:

①基本原则:互斥进入,如果一个进程在临界区中执行,其他进程不允许进入;

这些进程间的约束关系称为互斥 mutual exclusion;这保证了临界区;

好的临界区保护原则:

②有空让进:若干进程要求进入空闲临界区时,应尽快使一些进程进入临界区;

③有限等待:从进程发出进入请求到允许进入,不能无限等待;

解决竞争调价你的方法

值日算法(轮换算法)、买牛奶留标签算法(标签算法)、面包店算法(取号算法);

面包店算法的正确性:

n 互斥进入:Pi在临界区内,Pk试图进入,一定有(num[i],i)<(num[k],k),Pk循环等待;

n 有空进入:如果没有进程在临界区中,最小序号的进程一定能够进入;

n 有限等待:离开进阶区的进程再次进入一定排在最后(FIFO),所以任一个想进入进程至多等待n个进程;

软硬件协同设计;

关闭中断法:关闭中断cli=close interrupt,执行完临界区代码再开中断sti=start interrupt;

关闭中断,对于多CPU不好使;

硬件原子指令法:给一段指令上锁,锁的本质就是一个变量(整形变量),将变量赋值为某一个值,就锁住,执行完再赋值为另一个值,就解锁了;

原子指令,一条指令是原子的,要么被执行,要么没有执行,不可分割;

临界区指令:不能被中途打断的指令,

CPU调度

多个进程,应该选择哪个执行,这就是调度;

调度思想:

①按照先后顺序进行调度:

先来后到,谁先来,先执行谁;

②按照优先级进行调度:

任务短的可以适当优先;

调度目标:如何让进程满意,时间是关键,也就是快

n 尽快结束任务,周转时间短(从任务进入到任务结束)

n 用户操作尽快反应:响应时间短(从操作发生到响应)

n 系统内耗时间少:吞吐量(完成任务量)

如何做到合理?折中、综合考虑

n 吞吐量和响应时间之间有矛盾;

n 响应时间小→切换次数多→系统内耗大→吞吐量小;

n 前台任务和后台任务的关注点不同;

n 前台任务关注相应时间,后台任务关注周转时间;

n IO约束型任务和CPU约束型任务各有特点;

n IO优先级更高一些,更利于并行;

折中和综合让系统变得复杂,然而系统又要尽量简单;

 

调度算法

FCFS=First Come,First Served,先来先服务;体现公平;

SJF=short job first,短作业优先;周转时间最小;

RR=round Robin按时间片轮转调度;

时间片大:响应时间太长;时间片小,吞吐量小;折中:时间片10-100ms切换时间0.1-1ms(1%);

定义前台任务和后台任务两队列,前台RR,后台SJF,没有前台任务时才调度后台任务;

后台任务优先级动态升高,防止饥饿;执行一段时间后,必须再调低,防止前台任务响应迟钝;

 

调度函数schedule()

 

fork

fork英 /fɔːk/ 美 /fɔːrk/

n. 餐叉,叉子;耙,叉;岔路,支流;叉状部件,叉状物;

v. (道路、河流等)分岔,岔开;(用餐叉)叉起;耙地,叉掘;走岔路中的一条;

 

fork进程控制函数,叉子函数、分叉函数;形象的表示进程之间的切换;

作用: 创建新进程;函数原型: pid_t fork(void);需要包含头文件 <unistd.h>

返回值:成功,两次返回(子进程返回 0,父进程返回子进程 ID);若出错,返回 -1

pid_t getpid(void);获取当前进程id;get process id

pid_t getppid(void);获取当前进程的父进程id;get parent process id

fork 的一个特性是父进程所有打开的文件描述符都被复制到子进程中。

父进程和子进程每个相同的打开描述符共享一个文件表项;

父进程和子进程共享同一个文件偏移量;

在 fork 之后处理文件描述符有以下两种常见的情况。

(1) 父进程等待子进程完成,在这种情况下,父进程无需对其描述符做任何处理。当子进程终止后,它曾进行过读、写操作的任一共享描述符的偏移量已做了相应更新。

(2) 父进程和子进程各自执行不同的程序段,在这种情况下,在 fork 之后,父进程和子进程各自关闭他们不需使用的文件描述符,这样就不会干扰对方使用的文件描述符。

————————————————

fork 失败的两个主要原因是:

(1) 系统中已经有太多的进程

(2) 该实际用户 ID 的进程总数超过了系统限制,CHILD_MAX 规定了每个实际用户 ID 在任一时刻可拥有的最大进程数。

fork 的用法

(1) 一个父进程希望复制自己,使父进程和子进程同时执行不同的代码段。

(2) 一个进程要执行不同的程序,在这种情况下,子进程从 fork 返回之后立即调用 exec 系列

 

操作系统

 

操作系统概述

 

BIOS是英文"Basic Input Output System"的缩略词,就是"基本输入输出系统"。

BIOS是个人电脑启动时加载的第一个软件。

操作系统是计算机硬件和应用之间的一层软件;

操作系统是管理硬件的软件;

方便我们使用硬件,如显存;

高效使用硬件,如开多个端口;

没有操作系统的计算机叫做裸机;因此操作系统相当于计算机的衣服;

 

CPU管理、内存管理、终端管理、磁盘管理、文件管理、网络管理、电源管理、多核管理;

操作系统

应用软件

操作系统

计算机硬件

 

启动过程

1. 刚开机时CPU处于实模式

2. 开机时,CS=0xFFFF,IP=0x0000

3. 寻址0xFFFF0(ROMBIOS映射区)

4. 检查RAM、键盘、显示器、磁盘

5. 将磁盘0磁道0扇区读入0x7c00处

6. 设置cs=0x7c00,ip=0x0000

 

操作系统接口

POSIX:Portable Operating System Interface of Unix(IEEE制定的一个标准族)

接口表现为函数调用,又由系统系统,所以称为系统调用;

分类

POSIX定义

描述

任务管理

fork

创建一个进程

execl

运行一个可执行程序

pthread_create

创建一个线程

文件系统

open

打开一个文件或目录

EACCES

返回值,表示没有权限

mode_t st_mode

文件头结构:文件属性;

 

系统调用

主动进入内核的方法:中断指令int(interrupt)int 0x80

n int指令将使CS红的CPL改成0,以进入内核

n 这是用户程序发起的调用内核代码的唯一方式;

系统调用的核心

① 用户程序红包含一段包含int指令的代码

② 操作系统写中断处理,获取想要调用程序的编号;

③ 操作系统根据编号执行相应代码

 

将内核程序和用户程序隔离

区分内核态和用户态由于CS:IP是当前指令,所以用CS最低两位来表示:0是内核态,3是用户态;

内核态可以访问任何数据,用户态不能访问内核数据;对于指令跳转也一样,实现了隔离;

n 获取特权级:访问的数据段DS的最低两位,CPL(CS)RPL(RS)DPL (privilege level)

n 特权级判定:如果DPL>=CPL DPL>=RPL才能访问;

 

操作系统历史

①IBMSYS(1955-1965)

监控系统:实现任务批处理

②OS/360:(1965-1980)

360表示全方位服务,开发周期5000人年

需要让一台计算机干多种事

多道程序multiprogramming

作业之间的切换和调度称为核心,既有IO任务又有计算任务,需要让计算机CPU忙碌

③MULTICS多人使用(1965-1980)

每个人启动一个作业,作业之间快速切换

分时系统timesharing

代表:MIT MULTICS(MULTIplexed Information and Computer Service)

核心仍然是任务切换,但是资源复用思想对操作系统影响很大,虚拟内存就是一种复用;

④Unix(1980-1990)

Unix是一个简化的MULTICS

⑤Linux(1990-2000)

多进程结构是计算机的基本图谱;

⑥DOS:CPM QDOS MSDOS

Basic解释器

FAT管理磁盘

⑦Windows 可视化

n 多进程图谱ProcessView(CPU、内存);

n 文件操作视图FileView(IO、磁盘);

特权级=PL=Privilege Level

描述符特权级(DPL,Descriptor Privilege Level)

 

实施特权级保护的第一步,是为所有可管理的对象赋予一个特权级,以决定谁能访问它们。每个 Descriptor 都具有描述符特权级(DPL,Descriptor Privilege Level)字段,Descriptor 总是指向它所“描述”的目标对象,代表着该对象,因此该字段(DPL)实际上是目标对象的特权级。

 

当前特权级(CPL,Current Privilege Level)

 

当处理器正在一个代码段中取指令和执行指令时,那个代码段的特权级叫做当前特权级(Current Privilege Level, CPL)。 正在执行的这个代码段,其选择子位于段寄存器CS中,其最低两位就是当前特权级的数值。

请求特权级(RPL,Request Privilege Level)

 

RPL也就是指请求者的特权级别(Requestor’s Privilege Level)。

特权指令(Privileged Instructions)

 

不同特权级别的程序,所担负的职责以及在系统中扮演的角色是不一样的。计算机系统的脆弱性在于一条指令就能改变它的整体运行状态,比如停机指令hlt 和对控制寄存器CRO的写操作,像这样的指令只能由最高特权级别的程序来做。因此,那些只有在当前特权级 CPL 为 0 时才能执行的指令,称为特权指令(Privileged Instructions)。

输出特权级(I/O Privilege Level)

 

在处理器的标志寄存器EFLAGS中,位13、位12是IOPL位,也就是输入/输出特权级(I/O Privilege Level),它代表着当前任务的I/O特权级别。某些指令,例如IN,OUT,CLI需要 I/O 特权,这些操作根据 IOPL 和 CPL 确定合法性。

内存分段的意义

  • 在多任务环境下,系统中有多个程序在运行;
  • 程序之间需要隔离!
  • 分段是存储管理的一种方式,为保护提供基础;
  • 不同程序在不同段中;
  • 一个程序可以包含多个段;
  • 段用于封闭具有共同属性的存储区域;

 

,,

 

标签:操作系统,程序,笔记,学习,指令,内存,进程,页表
来源: https://www.cnblogs.com/zhangdezhang/p/16647459.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有