操作系统-系统资源代价管理-基于C++分析

文章讨论了操作系统中不同组件的代价,包括内存管理的内存空间、CPU时间和I/O带宽代价,以及如何通过内存池和减少内存分配来优化。进程管理中提到了上下文切换的开销,并推荐使用协程来减少切换代价。文件系统和网络系统的代价也进行了分析,提出通过缓存、优化访问方式和数据传输策略来降低资源消耗。文章强调了程序员可以主动控制和优化的系统资源使用,以提高性能和效率。
摘要由CSDN通过智能技术生成

目录

操作系统-代价管理

内存管理的代价

内存管理的代价-内存池

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

文件系统的代价

网络系统的代价

操作系统-结语


操作系统-代价管理

在操作系统中,总是存在各式各样的代价,很多代价是系统运行所必须的,但不是所有代价都是如此,这样,我们程序员便可以从中获取性能的优化。

内存管理的代价

内存管理的代价较多:

内存空间:操作系统需要占用一定的内存空间来管理系统内存,包括内存分配、回收和页表管理等。这些内存空间会减少可供应用程序使用的内存空间,从而影响系统的性能和稳定性。

CPU 时间:操作系统需要消耗一定的CPU时间来进行内存管理。例如,当系统需要分配内存时,操作系统需要扫描内存空闲块列表来查找可用内存块,这会消耗一定的CPU时间。如果内存空闲块列表很长,这个操作就会变得非常耗时。

I/O 带宽:操作系统需要频繁地进行内存读写操作,例如将数据从内存写入硬盘或从硬盘读取到内存。这些操作会占用系统的I/O带宽,从而影响系统的整体性能。

系统稳定性:内存管理是操作系统的核心功能之一,如果操作系统在内存管理上出现问题,可能会导致系统崩溃或运行不稳定。因此,操作系统需要投入大量的资源来保证内存管理的正确性和稳定性。

但是其中我们可以进行优化的部分:

减少内存分配和释放次数:频繁的内存分配和释放会导致系统频繁调度内存,从而增加系统资源的代价。可以通过预先分配一定大小的内存空间,避免频繁的内存分配和释放。

使用内存池:内存池是一种预先分配一定大小的内存空间的技术,可以避免频繁的内存分配和释放。程序员可以使用内存池来管理程序中的内存分配和释放。

避免内存泄漏:内存泄漏是指程序中申请的内存没有被正确释放,导致系统中的内存资源被占用,最终导致系统崩溃。程序员需要注意内存泄漏问题,并及时释放申请的内存空间。

内存管理的代价-内存池

减少存分配和释放次数与避免内存泄漏都是我们在日常编程的过程中需要注意的,其实没必要专门去说,这里需要注意的是内存池技术:

内存池是池化技术中的一种形式。通常我们在编写程序的时候回使用 new delete 这些关键字来向操作系统申请内存,而这样造成的后果就是每次申请内存和释放内存的时候,都需要和操作系统的系统调用打交道,从堆中分配所需的内存。如果这样的操作太过频繁,就会找成大量的内存碎片进而降低内存的分配性能,甚至出现内存分配失败的情况。而内存池就是为了解决这个问题而产生的一种技术。

每一次进行内存分配,就会消耗一次分配内存的时间,设这个时间为 T,那么进行 n 次分配总共消耗的时间就是 nT;如果我们一开始就确定好我们可能需要多少内存,那么在最初的时候就分配好这样的一块内存区域,当我们需要内存的时候,直接从这块已经分配好的内存中使用即可,那么总共需要的分配时间仅仅只有 T。当 n 越大时,节约的时间就越多。

内存池技术其实便是由用户自己去进行内存的管理,而不是由操作系统来分配,避免了复杂的操作系统调度环境,转而只需要专心管好自己的一篇小空间(相对而言)。

我们可以通过重载/替换new来完成基于内存池的内存分配,这样所有的小的频繁的内存申请都可以通过一个较小的内存池来统一管理。

在内存池中的申请空间在使用完毕以后(通过delete释放),内存池可以将这片使用完毕的内存初始化(也可以不初始化,交给用户来进行),然后放回未使用内存的链表中。

这样便可以通过两个链表来对内存池进行管理(一个已使用内存链表,一个未使用内存链表)。

在申请内存时,如果发现未使用内存链表内的内存长度不满足,也可以申请新的内存空间来放在未使用内存链表后。

或者拒绝内存的分配,重新申请一个池然后返回分配空间,这取决于内存池是否是可变长度/大小的。

不过内存池会有一个在多线程环境下的线程安全问题需要注意,不过也有较简单的解决方法,那便是给每一个线程一个自己的内存池来操作。如果需要两个线程都访问一个内存池,那便只能通过信号量/无锁/共享内存等方式来保证线程安全。

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

进程的调度势必会产生上下文的切换,上下文切换需要涉及大量的系统资源和时间,包括保存和恢复进程状态所需的CPU时间、内存空间和I/O操作。降低系统的性能和效率,因此需要尽可能地避免上下文切换。

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

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

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

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

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

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

协程具有以下的特点:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

文件系统的代价

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

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

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

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

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

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

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

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

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

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

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

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

这方面的代价管理的解决方法,我认为核心是减低对磁盘文件的读取次数,最好能做到不读取,或只在开始时读取一次,然后利用内存管理起来,尽可能的避免IO操作,毕竟这真的很慢。

其中,我认为延迟读取在系统资源较充裕的情况下,是需要避免的,所以我选择避开它,这样在需要拉取数据时,就可以避开较慢的IO操作了,毕竟延迟读取只适用于静态数据和不需要实时更新的数据。

大文件的读取需要避免多线程的同时读写文件,效率太底下了,不如在内存中进行,如果文件本身太大无法进行,就进行分段的操作,将其部分数据放在内存中进行操作。

在对大文件的操作不需要实时更新的情况下,我们也可以通过维护一个修改表来完成,这个表接收并记录所有对大文件的数据修改,同时计算所有记录最后的修改结果:

第一次:修改[3,2]的数据为原来的200%

记录 [3,2] 200%

第二次:修改[3,2]的数据为原来的200%

记录 [3,2] 400%

只需要记录最终的计算结果即可(也可以每一次都记录,这样便会支持日志系统),这样在最后写入数据时只需要最后读取一次文件然后计算一次结果便可以直接写入文件,可以减少很多的IO时间。

网络系统的代价

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

CPU资源:网络通信过程中,需要进行数据的封装、解封、加密、解密等操作,这些操作都需要消耗CPU资源。在高并发的情况下,CPU资源的消耗会更加明显。

内存资源:网络数据在传输过程中需要进行缓存,因此,操作系统的网络系统需要占用一定的内存资源。在高并发的情况下,网络数据的缓存会占用更多的内存资源。

带宽资源:网络通信需要使用带宽资源,带宽资源的消耗与数据传输的速率和数据量有关。在高并发的情况下,网络通信会占用更多的带宽资源。

磁盘资源:在使用网络文件系统时,需要进行文件的读写操作,这些操作会占用磁盘资源。在高并发的情况下,文件读写操作会更加频繁,磁盘资源的消耗也会更加明显。

在其中,我们可以优化:

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

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

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

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

这方面的代价管理的核心,我认为是数据,尽可能的减少发送的数据大小,减少发送数据的次数,减少等待数据的时间。

减少发送的数据大小:使用数据压缩算法,减少数据大小。

减少发送数据的次数:优化前后端的网络协议/约定,减少传输次数,只发送必要的数据。

减少等待数据的时间:尽量避免IO操作导致的等待,对于会频繁读取的磁盘文件,应该预先读取到内存中,通过线程池来讲多线程读取的文件发送出去(队列正好对应一个连接的端口)。

异步编程:编写异步的代码,避免在等待IO操作时不断进行上下文切换,提高系统的资源利用效率,降低系统代价消耗。

操作系统-结语

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

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

nameless_233

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

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

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

打赏作者

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

抵扣说明:

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

余额充值