加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_宿迁站长网 (https://www.0527zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

操作系统基础

发布时间:2022-12-03 09:33:23 所属栏目:Unix 来源:未知
导读: 目录
操作系统 Linux虚拟内存分布

虚拟地址从低地址到高地址
代码区(Text egment)
全局初始化数据区/静态数据区(Data Segment)
未初始化数据区(BSS)
堆区(heap)
栈区(stack)
静态对象的分

目录

操作系统 Linux虚拟内存分布

unix系统 下载_unix系统时间_unix 系统 下载

虚拟地址从低地址到高地址

代码区(Text egment)

全局初始化数据区/静态数据区(Data Segment)

未初始化数据区(BSS)

堆区(heap)

栈区(stack)

静态对象的分配与释放由编译器自动处理;动态对象的分配和释放必须由程序员自己显示的管理,通过malloc 和free两个函数来完成。

分这么多区域,主要是因为:

1) 一个进程在运行过程中,代码是根据流程依次执行的,只需要访问一次, 当然跳转和递归有可能使代码执行多次,而数据一般都需要访问多次,因此单独开辟空间以方便访问和节约空间.

2) 临时数据及需要再次使用的代码在运行时放入栈区中,生命周期短。 全局数据和静态数据有可能在整个程序执行过程中都需要访问,因此单独存储管理。

3) 堆区由用户自由分配,以便管理。

linux 32 位操作系统中,每个进程理论上有4G的独立内存空间,进程的内存空间按照text,data, bss, heap, stack由低到高分配,但是只增值到0xC0000000, 最后1G留给了内核。0~3G属于用户空间,3~4G为内核空间以上我们描述了一个运行的可执行程序 即一个进程的内存分布。

虚拟内存

基于局部性原理,当进程开始运行时,先将一部分程序装入内存,另一部分暂时留在外存;当要执行的指令不在内存时,由系统自动完成将它们调入内存的工作;当没有足够的内存时,系统自动选择部分内存(暂不执行的程序)空间,将其中原有的内容交换到磁盘上,并释放这些内存空间供其他进程使用。

这样做的结果使程序的运行丝毫不受影响,使程序在运行中感觉到拥有一个不受内存容量约束的、虚拟的、能够满足自己需求的存储器。

内存系统面临哪些问题?

内存(memory)资源永远都是稀缺的,当越来越多的进程需要越来越来内存时,某些进程会因为得不到内存而无法运行;内存容易被破坏,一个进程可能误踩其他进程的内存空间;

虚拟内存提供了哪些能力?

正如软件工程中的其他抽象,虚拟内存是操作系统物理内存和进程之间的中间层。它为进程隐藏了物理内存这一概念,为进程提供了更加简洁和易用的接口。这个中间层提供了三个重要的能力:

高效使用内存:VM将主存看成是存储在磁盘上的地址空间的高速缓存,主存中保存热的数据,根据需要在磁盘和主存之间传送数据;简化内存管理:VM为每个进程提供了一致的地址空间,从而简化了链接、加载、内存共享等过程;内存保护:保护每个进程的地址空间不被其他进程破坏

当内存资源不足时,Linux把某些页的内容转移至硬盘上的一块空间上,以释放内存空间。硬盘上的那块空间叫做交换空间(swap space),而这一过程被称为交换(swapping)。物理内存和交换空间的总容量就是虚拟内存的可用容量

虚拟地址映射物理地址?

直接映射

页表缓存映射

TLB映射

我们打开一个进程发一个指令,会生成一个虚拟地址,该虚拟地址中有虚拟页号和页偏移量,由虚拟页号和MMU中的页表寄存器(表示页表在主存当中的起始位置)做一个偏移,就可以找到与这个虚页号对应的页表项在主存当中的物理地址,如果有效位为1的话,表示当前主存有这个页,那么我们就将这个页表项取出来,也就是知道了物理页号,再用这个物理页号与虚拟地址中的页内偏移相拼接,这样就得到物理地址。这样实现了虚拟地址向物理地址转化的过程(页表缓存映射)

进程,线程,协程

(一)拥有资源

进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。

(二)调度

线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换。

(三)系统开销

由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。

(四)通信方面

进程间通信 (IPC) 需要进程同步和互斥手段的辅助,以保证数据的一致性。而线程间可以通过直接读/写同一进程中的数据段(如全局变量)来进行通信。

(五)进程有独立的地址空间,启动一个进程系统就会为它分配地址空间,建立数据表来维护代码段,堆栈段和数据段;线程共享进程中的数据,使用相同的地址空间。

操作系统调度的最小单位是线程,在单个线程中,协程一定是串行执行的

有了进程为何还需要线程

虽然进程有这么多优点,但是在多任务环境中,不可能说让所有任务排队,前面的处理完了才处理后面的任务。如果要让用户感觉到任务都是一起执行的,那么就必须在进程之间频繁切换。问题在于如果要进行进程的切换需要做很多的工作,必须要保存好当前CPU的上下文,好让CPU下次被分配到当前进程时可以继续往前执行,然后还需要设置新的进程的CPU上下文,在这个过程中会花费很多时间。由于这个原因就限制了系统中进程数目不能多。

为了解决这个限制,后来提出将进程的两个属性分开,由操作系统分开处理,即对于作为调度和分派的基本单位,但不同时作为拥有资源的单位;而对于拥有资源的基本单位,又不对其进行频繁的切换。正是在这种思想的指导下,形成了线程的概念。线程的切换则仅需保存和设置少量寄存器内容,不会同进程切换需求创建和销毁进程控制块等,所以非常迅速,所以其十分适合高并发环境。

为什么有了进程,还要引入线程呢? (使用多线程到底有哪些好处?)

(1)进程实现多任务的缺点:进程间切换计算机资源开销很大,切换效率非常低;进程间数据共享的开销也很大。

(2)从资源上来讲:和进程相比,它是一种非常“节俭”的多任务操作方式.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。

(3)从切换效率上来讲:运行于一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需的时间也远远小于进程间切换所需要的时间.据统计,一个进程的开销大约是一个线程开销的30倍左右。

(4) 从通信机制上来讲:线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过进程间通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便

协程

协程不是进程也不是线程,而是一个特殊的函数,这个函数可以在某个地方挂起,并且可以重新在挂起处外继续运行。所以说,协程与进程、线程相比并不是一个维度的概念。

协程上下文其实就是保存了当前所有寄存器的值,这些寄存器描述了当前的函数栈,程序执行状态等信息。

资源:占用资源很少。比如CPU起一个线程就要占用1M,而协程起一个只需要几K。

调度策略:用户空间决定,调度策略由应用层代码定义。而线程调度策略只能操作系统来确定

但是有一点必须明确的是,一个线程的多个协程的运行是串行的。如果是多核CPU,多个进程或一个进程内的多个线程是可以并行运行的,但是一个线程内协程却绝对是串行的,无论CPU有多少个核。毕竟协程虽然是一个特殊的函数,但仍然是一个函数。一个线程内可以运行多个函数,但这些函数都是串行运行的。当一个协程运行时,其它协程必须挂起。

而进程切换 CPU 时需要进行这两步:

为什么内存地址空间转换这么慢?Linux 实现中,每个进程的地址空间都是虚拟的,虚拟地址空间转换到物理地址空间需要查页表,这个查询是很慢的过程,因此会用一种叫做 TLB 的 cache 来加速,当进程切换后,TLB 也随之失效了,所以会变慢。

unix系统 下载_unix 系统 下载_unix系统时间

协程存在上下文的切换

1、进程的切换者是操作系统,切换时机是根据操作系统自己的切换策略,用户是无感知的。进程的切换内容包括页全局目录、内核栈、硬件上下文,切换内容保存在内存中。进程切换过程是由“用户态到内核态到用户态”的方式,切换效率低。

2、线程的切换者是操作系统,切换时机是根据操作系统自己的切换策略,用户无感知。线程的切换内容包括内核栈和硬件上下文。线程切换内容保存在内核栈中。线程切换过程是由“用户态到内核态到用户态”, 切换效率中等。

3、协程的切换者是用户(编程者或应用程序),切换时机是用户自己的程序所决定的。协程的切换内容是硬件上下文,切换内存保存在用户自己的变量(用户栈或堆)中。协程的切换过程只有用户态,即没有陷入内核态,因此切换效率高

有栈协程和无栈协程:

每个协程都拥有一个独立的栈帧, 协程切换时会保存当前协程栈中的所有数据, 并加载新的栈帧对象. 这样做的优点是: 协程调度可以在内存中的任意位置、任意时刻进行; 但是缺点也很明显: 随着并发量的增加, 协程的数目越来越多, 当前内存中的协程栈(无论是occupy还是suspend)越来越多, 内存瓶颈开始显现, 且内存切换本身也是不小的开销(寄存器恢复、数据拷贝). 所以, stackful coroutine一般有栈大小的限制(libco是128K).

那么能不能所有正在执行的协程都共享一个栈呢?这就是共享栈的思路. 共享栈将协程划分为协程组, 同一个协程组中的协程共享同一块内存, 在协程切换的时候将当前内存中的数据保存到运行协程的buffer中, 并将新调度协程buffer中的数据拷贝到共享栈中. 如此既可以减少内存开销, 同时运行协程又没有了栈大小的限制. 共享栈的缺点是: 协程调度产生的局部变量都在共享栈上, 一旦新的协程运行后共享栈中的数据就会被覆盖, 先前协程的局部变量也就不再有效, 进而无法实现参数传递、嵌套调用等高级协程交互.

用户态切换到内核态的3种方式

基本概念

系统调用

这是用户态进程主动要求切换到内核态的一种方式unix系统时间,用户态进程通过系统调用申请使 用操作系统提供的服务程序完成工作,比如前例中fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户 特别开放的一个中断来实现,例如Linux的int 80h中断。

外围设备的中断

硬件中断,进程执行过程中,好比说用户点击了什么按钮,触发了按键中断,要赶紧去处理这个中断啊,保存进程上下文,切换到中断处理流程,处理完了,恢复进程上下文,返回用户态(返回之前可能会进行进程调度,选择一个更值得运行的进程投入运行态),进程继续执行

异常

当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

进程/线程间同步

线程间没有通信,线程间通信也就是同步

进程同步的四种方法

1、临界区(Critical Section):通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。

优点:保证在某一时刻只有一个线程能访问数据的简便办法

缺点:虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。

2、互斥量(Mutex):为协调共同对一个共享资源的单独访问而设计的。

互斥量跟临界区很相似,比临界区复杂,互斥对象只有一个,只有拥有互斥对象的线程才具有访问资源的权限。

优点:使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。

缺点:①互斥量是可以命名的,也就是说它可以跨越进程使用,所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。

②通过互斥量可以指定资源被独占的方式使用,但如果有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,可以根据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成这个要求,信号量对象可以说是一种资源计数器。

3、信号量(Semaphore):为控制一个具有有限数量用户资源而设计。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。互斥量是信号量的一种特殊情况,当信号量的最大资源数=1就是互斥量了。

优点:适用于对Socket(套接字)程序中线程的同步。(例如,网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限制,只有不大于设定的最大用户数目的线程能够进行访问,而其他的访问企图则被挂起,只有在有用户退出对此页面的访问后才有可能进入。)

缺点:①信号量机制必须有公共内存,不能用于分布式操作系统,这是它最大的弱点;

②信号量机制功能强大,但使用时对信号量的操作分散,而且难以控制,读写和维护都很困难,加重了程序员的编码负担;

③核心操作P-V分散在各用户程序的代码中,不易控制和管理,一旦错误,后果严重,且不易发现和纠正。

4、事件(Event): 用来通知线程有一些事件已发生,从而启动后继任务的开始。

优点:事件对象通过通知操作的方式来保持线程的同步,并且可以实现不同进程中的线程同步操作。

缺点:

总结:

①临界区不是内核对象,只能用于进程内部的线程同步,是用户方式的同步。互斥、信号量是内核对象可以用于不同进程之间的线程同步(跨进程同步)。

②互斥其实是信号量的一种特殊形式。互斥可以保证在某一时刻只有一个线程可以拥有临界资源。信号量可以保证在某一时刻有指定数目的线程可以拥有临界资源。

进程间通信

管道pipe(共享文件):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

共享内存SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

套接字Socket:套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

进程有哪些状态?

unix系统 下载_unix 系统 下载_unix系统时间

进程的调度算法?

不同环境的调度算法目标不同,因此需要针对不同环境来讨论调度算法。

1. 批处理系统

批处理系统没有太多的用户操作,在该系统中,调度算法目标是保证吞吐量和周转时间(从提交到终止的时间)。

1.1 先来先服务

先来先服务 first-come first-serverd(FCFS)

按照请求的顺序进行调度。

有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长。

1.2 短作业优先

短作业优先 shortest job first(SJF)

按估计运行时间最短的顺序进行调度。

长作业有可能会饿死,处于一直等待短作业执行完毕的状态。因为如果一直有短作业到来,那么长作业永远得不到调度。

1.3 最短剩余时间优先

最短剩余时间优先 shortest remaining time next(SRTN)

按估计剩余时间最短的顺序进行调度。

2. 交互式系统

交互式系统有大量的用户交互操作,在该系统中调度算法的目标是快速地进行响应。

2.1 时间片轮转

将所有就绪进程按 FCFS (先来先服务) 的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。

时间片轮转算法的效率和时间片的大小有很大关系。因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。

2.2 优先级调度

为每个进程分配一个优先级,按优先级进行调度。

为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。

(编辑:云计算网_宿迁站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!