操作系统与资源消耗代价-复习串联

内存管理

操作系统内存管理是操作系统的重要功能之一。其主要任务是对计算机系统中的内存进行有效的管理,包括内存分配、内存回收、内存保护等。内存管理的重点、特点和算法如下:

1.重点:

内存管理的重点是有效地利用计算机系统中的内存资源,尽可能地提高内存利用率,同时保证系统的安全和稳定。

2.特点:

(1)虚拟内存技术:操作系统通过虚拟内存技术将磁盘空间虚拟化为内存,从而扩大了系统内存的容量。

(2)内存保护:操作系统通过内存保护技术,保护系统的关键数据和程序不被非法访问和修改。

(3)内存分配:操作系统需要对内存进行分配和回收,保证内存的有效利用。

3.算法:

(1)分页式存储管理:将物理内存划分为若干个固定大小的物理块,将程序和数据也划分为若干个大小相等的逻辑块,称为页面。

(2)分段式存储管理:将程序和数据划分为若干个不同长度的逻辑块,称为段,每个段可以有不同的访问权限。

(3)段页式存储管理:将物理内存划分为若干个固定大小的物理块,每个物理块可以划分为若干个大小相等的逻辑块,即页,而程序和数据则划分为若干个不同长度的逻辑块,即段。该算法综合了分段式存储管理和分页式存储管理的优点。

总之,内存管理是操作系统的重要功能之一,其重点在于有效地利用内存资源,特点在于虚拟内存技术和内存保护技术,算法包括分页式存储管理、分段式存储管理和段页式存储管理等。(上述的算法其实都可以用链表实现,简单易懂,就是效率不算最高)

现在我们来说一下现代的操作系统

现代操作系统实现内存管理主要包括物理内存管理和虚拟内存管理两个方面。物理内存管理主要涉及程序的装入、交换技术、连续分配管理和非连续分配管理,包括分页、分段和段页式等方式。而虚拟内存管理主要包括虚拟内存概念、请求分页管理方式、页面置换算法、页面分配策略、工作集和抖动等。

虚拟内存的实现是将虚拟地址空间分解成页,并将每一页映射到物理内存的某个页框或者解除映射。转换检测缓冲区(TLB)提供中间由虚拟地址转换为物理地址时的缓存,可以直接将虚拟地址映射到物理地址,加速分页过程。常用的页面置换算法包括FIFO、LRU、LFU、NUR和随机算法等,其中LRU算法是最常用的一种,基于页面的历史访问情况进行页面置换。

除此之外,操作系统还会将虚拟地址划分为内核空间和用户空间,用户进程只能访问用户空间的虚拟地址,只有通过系统调用、外设中断或异常才能访问内核空间[2]。同时,操作系统也会对内存节点进行分区,将节点分为DMA、Normal和High Memory内存区,以及采用多级页表和倒排页表等方式处理巨大的虚拟地址空间。

总的来说,现代操作系统采用多种策略和算法来实现内存管理,以提高系统的性能和稳定性。

值得注意的一点是,现代的操作系统总体来说,使用的分段+分页,但是巧妙的分段内存设计,相当于把分段的概念给屏蔽了:

某个程序的中断上下文段寄存器

cs: 001b

ds: 0023

ss: 0023

es: 0023

只有0x001b和0x0023两个值,这不是一个地址,而是一个段选择子,按照段选择子的格式展开来看这两个值指向的是哪个段描述符:

十六进制:001b

二进制:0000000000011 0 11 - 段序号:3 - 表类型:GDT - 特权级:Ring3

十六进制:0023

二进制:0000000000100 0 11 - 段序号:4 - 表类型:GDT - 特权级:Ring3

也就是说,cs段指向的是GDT中的第3个表项,其他三个寄存器指向的是GDT中的第4个表项。

接下来,我们来看一下这个神秘的GDT里面的内容到底是什么?很多人学了内存管理,可能还从来没看过真实的GDT里面到底是什么数据吧。

GDT是位于操作系统内核地址空间中的,在Windows上有两种查看方式,一种是通过Windbg,一种是通过一些ARK工具,我这里选择使用PChunter这个神器进行查看。

前面提到过,GDT中的表项是段描述符,这是一个比较复杂的数据格式,好在,这个神器对段描述符进行了解析,使用表格字段的方式进行了展示,让我们看起来轻松多了。

第3个表项和第4个表项,它们的基地址都是0x00000000。

再看它们的界限值,都是0x000FFFFF,界限的单位不是字节而是Page/页,把这个值乘以页面的大小4KB,就是0xFFFFF000。也就说这个段的上限到了0xFFFFF000这个页面,再把这一个页面的大小加进去,就是0xFFFFFFFF了!

所以,重点来了!看到了吗,GDT中的第3个和第4个表项所描述的这两个段,它们的基地址都是0x00000000,整个段的大小都是0xFFFFFFFF,这意味着什么?这意味着整个进程的地址空间实际上就是一个段!

也就是说:进程的代码段、数据段、栈段、扩展段这四个段全部重合了,而且是整个进程地址空间共计4GB成为了一个段。

说起来是分段,实际上等于没分了,再加上段的基地址全部是0,那进行地址翻译的时候,有没有段都没什么区别了。

总结:操作系统实际上把段给架空了。

注:

不过不是所有的64 位所有段偏移都会被当做 0 对待, FS 和 GS 是例外。事实上 Linux x64 GCC 就经常用 FS 加上一个立即数偏移来访问内存中的 canary 值。

这里关于分段/分页的内容,来自:

知乎-现代操作系统内存管理到底是分段还是分页,段寄存器还有用吗?

现代操作系统内存管理到底是分段还是分页,段寄存器还有用吗? - 知乎

内容相当具有深度。

进程间通信

现代操作系统提供了多种进程间通信(IPC)的方式,下面介绍一些常见的进程间通信方法:

管道:管道是一种半双工的通信方式,数据只能单向流动。管道分为匿名管道和命名管道两种。匿名管道只能在具有亲缘关系的进程间使用,而命名管道可以在不同进程之间进行通信。管道的缺点是只能传递简单的字节流,不能传递复杂的数据类型和结构体等。

消息队列:消息队列是一种消息传递机制,可以实现异步通信,不同进程间通过消息队列发送消息,接收方从队列中获取消息并进行处理。消息队列是一种可靠的进程间通信方式,能够保证消息的可靠传输,但是消息队列需要操作系统提供支持。

共享内存:共享内存是一种将内存映射到多个进程的机制,多个进程可以直接访问同一块物理内存,从而实现高速数据交换。共享内存通常需要配合信号量或其他同步机制使用,以确保多个进程对共享内存的访问不会发生冲突。

信号量:信号量是一种计数器,可以用来同步多个进程对共享资源的访问。当一个进程需要访问共享资源时,先对信号量进行操作,若计数器大于0,则允许进程访问并将计数器减1,否则进程等待。信号量常用于进程同步和进程互斥等场景。

套接字:套接字是一种通用的进程间通信机制,可以在不同计算机之间进行通信。套接字通常用于网络通信,但也可以用于本地进程间通信。

信号(UNIX和LINUX):响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动。通常信号是由一个错误产生的。但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获。

事件(WINDOWS):是一种同步对象,主要用于在进程间通信与线程同步,事件分为自动重置事件和手动重置事件两种类型,事件对象还有两种状态:未信号状态和信号状态。

自动重置事件:当一个线程或进程等待一个自动重置事件时,如果该事件处于未信号状态,那么该线程或进程会立即阻塞等待。当事件被信号后,操作系统会自动将事件重置为未信号状态,并唤醒等待该事件的线程或进程中的一个。此时,如果有多个线程或进程等待该事件,只有一个线程或进程会被唤醒。

手动重置事件:当一个线程或进程等待一个手动重置事件时,如果该事件处于未信号状态,那么该线程或进程会立即阻塞等待。当事件被信号后,操作系统不会自动将事件重置为未信号状态,需要手动调用函数将事件重置为未信号状态。此时,如果有多个线程或进程等待该事件,所有等待的线程或进程都会被唤醒。

未信号状态表示事件还没有被信号,等待线程或进程需要等待事件被信号后才能继续执行。信号状态表示事件已经被信号,等待线程或进程可以继续执行。

特点:

可以在同一台计算机或网络中的不同计算机上进行(部分)。

可以实现不同进程之间的数据共享和协作,提高计算机系统的效率和性能。

可以实现异步通信,提高系统的可靠性和稳定性。

进程管理

操作系统实现进程管理的方式主要包括进程调度、进程同步和进程通信等方面。

进程调度:

进程调度是指操作系统在多个进程之间分配CPU资源的过程。操作系统会根据不同的调度算法,从就绪队列中选择一个合适的进程来运行。常见的调度算法包括先来先服务(FCFS)、最短作业优先(SJF)、时间片轮转(RR)等。其中,时间片轮转是最常用的调度算法之一,它可以平衡不同进程之间的优先级,避免进程饥饿问题。

进程同步:

进程同步是指操作系统在多个进程之间协调和控制资源的访问,避免竞争条件和死锁等问题。常见的进程同步机制包括信号量、互斥锁、条件变量等。其中,信号量是最常用的进程同步机制之一,它可以保证多个进程之间对共享资源的访问是有序的,并避免了竞争条件和死锁等问题。

进程通信:

进程通信是指操作系统在多个进程之间传递信息和数据的过程。常见的进程通信机制包括管道、消息队列、共享内存、信号量等。其中,共享内存是最快的进程通信方式之一,它可以将内存映射到多个进程中,从而实现高速数据交换。

特点:

1. 进程管理可以实现多个进程的并发执行,提高系统的效率和性能。

2. 进程管理可以控制和管理进程的资源分配和使用,避免资源竞争和浪费。

3. 进程管理可以实现进程之间的通信和协作,提高系统的可靠性和稳定性。

算法:

1. 进程调度算法:常见的进程调度算法包括先来先服务、最短作业优先、时间片轮转等。其中,时间片轮转是最常用的调度算法之一。

2. 进程同步算法:常见的进程同步算法包括信号量、互斥锁、条件变量等。其中,信号量是最常用的进程同步机制之一。

3. 进程通信算法:常见的进程通信算法包括管道、消息队列、共享内存、信号量等。其中,共享内存是最快的进程通信方式之一。

总之,进程管理是现代操作系统中的重要组成部分,它可以实现多个进程之间的并发执行、资源分配和管理、进程通信和协作等功能。在实现进程管理时,需要考虑多种因素,包括调度算法、同步算法和通信算法等,从而达到优化系统性能和提高系统可靠性的目的。

进程管理的代价-上下文切换

进程的调度势必会产生上下文的切换:

从一个进程切换到另一个进程时,操作系统需要保存当前进程的上下文信息,并恢复下一个进程的上下文信息。上下文切换会消耗系统资源和时间,降低系统的性能和效率,因此需要尽可能地避免上下文切换。

同时,上下文切换也会牵扯到内核态与用户态的转换(因为中间需要执行操作系统的调度算法,这是内核的代码部分):

用户态:指进程在执行普通用户代码时所处的状态。

内核态:指进程在执行操作系统内核代码时所处的状态。

我们可以很容易的看出上下文的切换会消耗宝贵的CPU存储资源,所有我们需要避免这种上下文切换的代价,那么问题来了,我们无法控制操作系统的调度算法,如何减小这种代价呢?

这里我们不能使用线程来避免,因为这也是操作系统创建,控制切换的,也就是说,线程也会产生上下文切换的代价,我们需要使用更轻量的线程——协程来避免内核级的上下文切换。

协程是一种用户级别的轻量级线程,不同于操作系统内核级别的线程。

协程具有以下的特点:

协程是由程序员自己进行管理和调度的,程序员需要手动控制协程的创建、切换和销毁。

协程是以协作式的方式进行调度,一个协程需要主动让出CPU资源,才能切换到下一个协程。

协程之间共享同一块栈空间,减少了内存的使用,同时也方便了数据共享和传递。

协程的上下文切换由程序员进行管理,只需要保存和恢复少量的上下文信息,成本比较低。

协程的上下文切换是基于用户态的,不会有内核态的中间转变,可以减少程序的资源开支,协程之间共享同一块栈空间,也减少了内存的使用,对于提高系统的效率而言是很好的。

这里写出线程与协程的代价对比:

上下文切换的开销:线程的上下文切换是由操作系统进行管理的,需要保存和恢复寄存器、程序计数器等多个上下文信息,成本比较高。而协程的上下文切换由程序员进行管理,只需要保存和恢复少量的上下文信息,成本比较低。

切换的频率:由于线程是由操作系统进行管理的,线程的切换频率比较高,因为操作系统需要根据调度算法进行线程的切换。而协程是由程序员进行管理的,协程的切换频率相对较低,因为程序员可以手动控制协程的切换。

内存的开销:由于线程是由操作系统进行管理的,每个线程都有自己的栈空间和堆空间,因此线程的内存开销比较大。而协程之间共享同一块栈空间,减少了内存的使用,降低了内存的开销。

综上所述,协程的上下文切换代价比线程低,因为协程的上下文切换只需要保存和恢复少量的上下文信息,而线程的上下文切换需要保存和恢复大量的上下文信息。协程的切换频率相对较低,因为程序员可以手动控制协程的切换。由于协程之间共享同一块栈空间,减少了内存的使用,因此协程的内存开销也比线程低。

除了协程以外,我们也有其他的方法来避免上下文切换,协程是通过不使用内核态来解决这个问题,那么我们也可以减少上下文切换来减少系统资源的消耗——避免阻塞操作。

阻塞操作会导致进程或线程的休眠,等待某个事件的发生。当事件发生时,操作系统会将进程或线程唤醒,从而引发上下文切换。因此,需要尽可能地避免阻塞操作,采用异步操作或非阻塞式操作来实现任务的执行。

除了上下文的切换代价以外,我们还有:

内存开销:每个进程需要占用一定的内存空间,包括代码段、数据段、堆栈段等。随着进程数量的增加,系统的内存使用量也会相应增加。

调度算法开销:进程调度算法需要占用一定的系统资源和时间,从就绪队列中选择一个合适的进程来运行。不同的调度算法会产生不同的代价和效果。

进程同步开销:多个进程之间的同步和通信需要使用一定的同步机制和通信机制,例如信号量、管道、共享内存等。这些机制会产生一定的系统资源代价和性能开销。

其中,可以由我们程序员去控制的代价不多:

减少进程数量:减少进程的数量可以降低系统的内存开销、上下文切换开销和调度算法开销等。程序员可以通过合理地设计和实现进程通信和协作机制,将多个功能相似的进程合并为一个进程,从而减少进程数量,降低系统的资源代价。

使用合适的调度算法和同步机制:调度算法和同步机制会影响系统的性能和效率。程序员可以根据具体的应用场景选择合适的调度算法和同步机制,从而减少系统的资源代价。

合理地使用文件和数据:文件和数据的访问会占用一定的系统资源和存储空间。程序员可以通过缓存、压缩、分区等方式,合理地使用文件和数据,降低系统的资源代价。

文件系统开销:进程需要访问文件和数据,需要使用文件系统来进行管理和存储。文件系统会占用一定的系统资源和存储空间。

注:上下文的部分已经详细介绍,不再赘述。

我们不能盲目的跟随系统的进程调度,需要自己主动的去减少一些不必要的资源消耗。

文件系统

件系统是通过将磁盘分成一个个固定大小的块,每个块作为最小的数据单位进行管理和存储。文件系统将文件抽象为一个个逻辑块,再将逻辑块映射为磁盘块,从而实现了文件的存储、读取和管理。下面重点讲述文件系统的特点和算法。

文件系统的特点:

抽象性:将物理存储设备抽象为逻辑块,将文件抽象为一组逻辑块,用户可以通过文件名等方式来访问文件。

透明性:屏蔽了磁盘物理结构的细节,用户不需要关心具体存储位置和物理块大小等信息,只需要通过文件名等方式即可访问文件。

可靠性:提供了对文件的备份和恢复功能,可以防止数据丢失和损坏。

安全性:提供了文件的访问控制和权限管理等功能,可以保护文件的安全性。

算法:

文件分配算法:文件系统需要决定如何分配磁盘空间给文件,常用的算法有连续分配、链式分配、索引分配等。

文件管理算法:文件系统需要管理文件的元数据信息,如文件名、大小、创建时间等,常用的算法有目录结构、文件控制块等。

磁盘调度算法:文件系统需要管理磁盘的读写操作,常用的算法有先来先服务、最短寻道时间优先、扫描算法等。

总之,文件系统是操作系统的重要组成部分,实现了对文件的存储、读取和管理,具有抽象性、透明性、可靠性和安全性等特点,需要使用合适的算法来实现文件的分配、管理和调度等操作。

文件系统的实现需要消耗系统的各种资源,包括以下几个方面:

磁盘空间:文件系统需要使用磁盘空间来存储文件和元数据信息,磁盘空间的大小取决于文件的数量、大小和文件系统的设计。

内存空间:文件系统需要使用内存空间来缓存文件数据和元数据信息,以提高文件的读取和写入效率。内存空间的大小取决于文件的访问模式和文件系统的设计。

CPU 时间:文件系统需要使用CPU时间来执行各种操作,如文件的分配、读取和写入等。CPU时间的消耗取决于文件系统的实现方式和算法。

网络带宽:文件系统需要使用网络带宽来支持远程访问和文件共享,网络带宽的消耗取决于文件的传输量和网络的负载情况。

这些都是会产生系统资源的消耗,而我们程序员可以采取以下几种方式来避免文件系统的代价:

合理使用缓存:程序员可以在代码中使用缓存技术,将常用的文件数据和元数据信息缓存到内存中,以减少对磁盘和网络的访问。但是,缓存的使用需要注意缓存大小和缓存策略等问题,以避免缓存过大或者缓存策略不当导致性能下降的问题。

优化文件访问方式:程序员可以通过优化文件的访问方式来减少文件系统的代价。例如,可以采用批量读取和写入数据的方式来减少磁盘访问的次数,以提高磁盘的读写效率。

避免频繁的文件操作:程序员可以避免频繁地打开、关闭和删除文件等操作,以减少文件系统的负载。例如,可以将多个操作合并为一个操作,以减少磁盘访问的次数和时间。

优化算法和数据结构:程序员可以通过优化算法和数据结构来减少文件系统的代价。例如,可以采用高效的文件分配算法和磁盘调度算法,以提高文件系统的性能和效率。

避免过度使用网络带宽:如果文件系统需要支持远程访问和文件共享,程序员可以避免过度使用网络带宽,例如,可以采用压缩和数据加密技术来减少网络传输的数据量和安全风险。

综上所述,程序员可以通过合理使用缓存、优化文件访问方式、避免频繁的文件操作、优化算法和数据结构、避免过度使用网络带宽等方式来避免文件系统的代价,以提高程序的性能和效率。

网络系统

实现网络系统的主要方式是通过网络协议栈的实现,网络协议栈是操作系统内核中用于实现网络通信的重要组成部分。网络协议栈的主要功能包括数据传输、错误检测、数据分段、数据重组等。下面重点讲述操作系统实现网络系统的特点、重点和算法。

特点:

多用户支持:操作系统必须支持多用户和多任务,并能够控制用户和任务的访问权限,保证网络系统的安全性。

可靠性:网络系统需要保证数据传输的可靠性,操作系统需要实现各种错误检测和纠正机制,例如CRC校验、冗余传输等。

性能:网络系统需要保证高效的数据传输和响应速度,操作系统需要实现高效的数据缓存、调度算法等。

可扩展性:网络系统需要支持不同的网络协议和传输协议,操作系统需要支持多种网络协议栈的实现,并支持动态加载和卸载。

重点:

网络协议栈的实现:网络协议栈是操作系统中实现网络通信的核心组件,包括物理层、数据链路层、网络层、传输层和应用层等。操作系统需要实现不同的网络协议栈,例如TCP/IP协议栈、IPX/SPX协议栈等。

网络缓存管理:操作系统需要实现高效的网络缓存管理,包括数据缓存和路由缓存等。数据缓存用于缓存网络数据,路由缓存用于缓存网络路由信息,提高网络传输效率。

网络调度算法:操作系统需要实现高效的网络调度算法,包括数据传输调度和路由选择算法等。数据传输调度算法用于调度网络数据传输,路由选择算法用于选择最优的网络路由。

算法:

TCP/IP协议栈实现算法:TCP/IP协议栈是目前最广泛使用的网络协议栈之一,其实现算法包括数据分段算法、拥塞控制算法、重传机制等。

数据传输调度算法:数据传输调度算法包括最短路径算法、最小带宽路径算法、最大流量算法等,用于调度网络数据传输。

路由选择算法:路由选择算法包括最短路径算法、贪心算法、遗传算法等,用于选择最优的网络路由。

综上所述,操作系统实现网络系统需要考虑多个方面,包括多用户支持、可靠性、性能和可扩展性等。重点是实现网络协议栈、网络缓存管理和网络调度算法等。算法方面包括TCP/IP协议栈实现算法、数据传输调度算法和路由选择算法等。

在其中,我们程序员可以优化的部分:

CPU资源:可以通过编写高效的代码和使用优化算法来减少CPU资源的使用,例如使用多线程、异步IO等技术来提高CPU利用率。

内存资源:可以通过优化内存管理和垃圾回收机制来减少内存资源的使用,例如使用对象池、延迟初始化等技术来降低内存占用。

网络带宽:可以通过优化网络传输算法和数据压缩算法来减少网络带宽的使用,例如使用数据压缩、分块传输等技术来降低数据传输量。

磁盘空间:可以通过优化数据存储算法和数据压缩算法来减少磁盘空间的使用,例如使用压缩存储、数据分块等技术来降低数据占用空间。

可以使用的方法:

代码优化:编写高效的代码,避免浪费系统资源,例如避免重复计算、避免频繁创建和销毁对象等。

算法优化:优化算法,减少资源占用,例如选择合适的数据结构、使用缓存等。

异步编程:使用异步编程技术,减少等待时间,提高系统资源利用率。

数据压缩:使用数据压缩算法,减少数据传输量,降低网络带宽和磁盘空间的使用。

缓存技术:使用缓存技术,减少数据访问次数,提高系统性能和效率。

结语

我们可以看到操作系统在实现整体中,有很多的系统资源使用代价,但是这些代价不是必须的,是我们可以避免的,在这个技术日新月异的时代,可以避免的技术肯定也不止这些,但是我水平也就这样(目前),所有我们不能停止对系统的探索,不能停止对程序的优化。

毕竟C++的对底层资源的开放,代表了C++强调“底层控制”的思想。C++的设计初衷是为了提供一种高级的编程语言,同时也具有直接操作底层资源的能力,使程序员可以更加灵活、高效地开发软件系统,那么我们便不能辜负语言对我们的信赖。

注:关于文件系统与网络系统的部分写的比较省略,了解不深入,不敢写的太深,怕闹笑话。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nameless_233

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值