前端看这里面经时间很少。
1. 什么是用户态和内核态?为什么要区分内核态和用户态?
(1)用户态和内核态是两种执行规则,用户态下,应用程序不能直接访问硬件或者进行特权操作,需要通过系统调用让内核进行对系统资源的操作。内核态是指操作系统内核进行工作时,具有最高权限,能直接访问硬件资源和进行各种特权操作(比如内存管理、进程调度)。
(2)系统调用或者硬件中断时,会进入内核态。
(3)CPU在运行应用程序时,执行用户态的规则,当内核在运行时,执行内核态的规则。
用户态和内核态是操作系统的两种运行状态。
内核态:处于内核态的 CPU 可以访问任意的数据,包括外围设备,比如网卡、硬盘等,处于内核态的 CPU 可以从一个程序切换到另外一个程序,并且占用 CPU 不会发生抢占情况,一般处于特权级 0 的状态我们称之为内核态。用户态:处于用户态的 CPU 只能受限的访问内存,并且不允许访问外围设备,用户态下的 CPU 不允许独占,也就是说 CPU 能够被其他程序获取。
为什么要区分?
这个主要是访问能力的限制的考量,计算机中有一些比较危险的操作,比如设置时钟、内存清理,这些都需要在内核态下完成,如果随意进行这些操作,那你的系统得崩溃多少次。
设置权限,避免随意的危险操作
2. 什么是操作系统?谈谈对操作系统的理解?操作系统是用来干嘛的?
(1)操作系统就是管理电脑的各种资源,相当于一个大管家,处理计算机中的大小事务,保持计算机的运行。主要就是负责管理和协调计算机硬件资源,为应用程序提供运行环境和服务。
(2)操作系统主要功能就是资源分配、进程管理、文件管理、用户界面交互(命令行或者GUI图形化页面)、错误检测和恢复。
3. 并发和并行的区别?
并行指的是,同一时间内执行多个任务,需要硬件的支持,比如多核心或者多处理器。并发就是让任务交错进行,CPU通过时间片轮转或者任务切换策略, 在各个任务之间快速切换,给人这些任务在同时执行的错觉。
举个例子,现在有两个任务需要执行,电脑只有单核CPU,那么需要交错执行达到并发,让这些任务仿佛同一时间都得到相应,如果有多核CPU,就可以分配给每个核心不同的任务,同时执行,达到并行。
并发是交替执行多个任务,让人感觉这些任务在同时执行。并行就是一个时间段内有多个任务都在执行。
4. 同步和异步的区别?
简单的说,同步就是要等目前的步骤完成才能进行下一步,异步就是不需要等待当前任务完成,可以执行其他操作。
5. 阻塞和非阻塞的区别?
阻塞就是等待结果时暂停执行任务,就像有阻塞物,被阻塞了。非阻塞就是等待结果时可以继续执行其他任务。
阻塞适用于需要确保结果完整性和依赖顺序的情况,非阻塞使用于提高并发性和响应性的情况。
6. 什么是进程?进程和线程有什么区别?什么是线程?为什么有了进程还需要线程?
(1)进程是正在运行的程序实例,当程序执行时,操作系统就会创建一个独立的进程。
线程是进程内的一个执行单元,一个进程内可以有多个线程,多个线程可以并发执行
(2)进程是资源分配的最小单位,线程是CPU分配的最小单位。
(3)为什么有了进程还要线程?
因为进程之间是相互独立的,进程是一个应用程序。进程之间的通信,创建销毁进程成本较大。我们在进程里设置线程,单个进程里的线程可以共享进程的资源所以线程间的通信会比进程间的通信快得多,创建或撤销一个线程也比创建或撤销一个进程来得快。
在单个进程内运行多个线程可以提高系统并行处理能力,使得CPU的利用率更高,提高系统的并发性能。
其它区别:
资源消耗不同:进程时需要为其分配独立的内存空间和系统资源,创建和切换进程的开销较大。线程间共享进程的资源,创建线程所需的开销较小,线程切换的开销也远小于进程切换。
通信方式:因为各自独立的内存空间,进程间通信(PC)较为复杂,需要使用管道、消息队列、共享内存、套接字等方式。同一进程内的线程共享内存 空间,因此线程直接读写内存即可,但注意需要使用同步机制避免数据错误。
进程可以看作独立应用,线程不能。
线程之间可以直接共享同一进程中的资源,进程之间需要通过进程通信共享资源。
进程开销比线程大。
7. 进程有哪些常见状态?
进程常见有5中状态,分别是 运行状态、等待状态、就绪状态、创建状态、终止状态。
8. 一个进程可以创建多少线程?
一个进程可以创建的线程数目由其系统资源限制,比如内存、CPU等
想象一家公司(进程)里面有很多员工(线程),这个公司有多少员工其实是取决于公司的资源情况,比如多大的办公面积,有多少办公设备等。一家小公司可能只有十几个员工,而一家大公司可能有上千个员工。然而,如果一个公司无限制的招聘员工,但却没有足够的空间或设备容纳这么多人,那么公司的运行将会变得非常低效。同样的,一个进程创建过多的线程,也会导致系统资源的消耗过大,从而影响系统的性能。
9. 进程间的通信方式有哪些?各自有什么优缺点?
进程间通信(IPC)有6种方式。包括管道通信、消息队列通信、共享内存通信、信号通信、套接字通信、信号量通信。
管道是最早的进程间通信机制,数据可以在父子或兄弟进程间单向流动。管道的优点是简单易用,但缺点是数据只能在有亲缘关系的进程之间传输,并且是无格式的字节流,需要进程自行解析。
消息队列是一种先进先出的队列结构,允许进程将消息发送到队列,并允许其他进程根据消息的优先级从队列中读取。优点是可以在无关进程间传输数据,支持数据的优先级设定。缺点是数据读写需要系统调用,消耗相对较高,复杂消息可能需要额外处理逻辑。
共享内存允许多个进程访问同一块内存空间,是最快的IPC方式(进程间通信最快的方式) 。优点是无需系统调用,直接读写内存,效率较高。缺点是需要手动解决进程间的同步问题,开发难度相对较高。
信号是一种简单的进程间通信方式,用来通知接收进程有某事件发生。它的优点是简单,可以异步地通知事件。缺点是信息量有限,只能传递一个数量,不能携带更复杂的信息。
套接字可以在不同机器上的进程间通信。它的优点是可以进行跨机器的通信,通用性强。缺点是开发相对复杂,数据读写需要系统调用,效率较低。
信号量常用于多个进程间的同步和互斥问题。
10. 线程间的通信方式有哪些?各自有哪些优缺点?
线程间的通信方式通常利用同一个进程下线程所共享的资源来实现。主要有5种方式:
锁机制、信号量、条件变量、事件驱动、线程本地存储
11. 进程的地址空间里面有什么?
进程的地址空间里有代码段、数据段、堆、栈。
12. 线程切换要保存哪些上下文?为什么要保存?
发生线程切换时,操作系统保存当前线程的“上下文”,以便在下次线程被再次调度执行时能接着上次运行状态运行。
保存的上下文包括寄存器值、堆栈指针、程序计数器、内核栈指针、线程状态、虚拟内存信息
13. 什么是协程吗?和线程有什么区别?
协程是一种用户级别的轻量级线程。它们的调度完全由用户控制,而不是由操作系统内核控制。与线程不同,协程的上下文切换极其快速且成本低,主要因为它所需保存和恢复的状态较少。
线程适合cpu密集型任务; 协程适合IO密集型任务。
14. 什么是僵尸进程?孤儿进程?
僵尸进程是一个已经结束执行的子进程,但其父进程尚未调用wait()或``waitpid()函数来获取子进程的终止状态信息。在这种情况下,子进程的进程控制块(PCB)仍然存在系统中,但没有正常退出,因此处于僵尸状态。
简单地说,就是执行结束了但是没有销毁还存在系统中的子进程。
僵尸进程是指在父进程没有及时回收子进程终止状态时,子进程成为已经结束但仍占用系统资源的状态。
僵尸进程与孤儿进程
僵尸进程(Zombie Process):子进程已经终止,但其父进程未对其进行回收(调用wait函数)。僵尸进程占用系统的进程表项,但不再消耗其他资源。操作系统会等待其父进程来获取它的终止状态信息,清除僵尸进程。
孤儿进程(Orphan Process):父进程提前终止,子进程继续运行,成为孤儿进程。操作系统会将孤儿进程托管给init进程(Linux系统中的PID为1的进程),由init进程来收养并清理这些孤儿进程。
僵尸进程就是 子进程比父进程先结束,但是父进程没有释放掉子进程占用的资源,子进程的进程描述符 仍然保留在系统中。
孤儿进程就是 父进程结束了,但它的子进程还在运行,那所有的子进程都会成为孤儿进程,并由init进程接管,对他们完成状态收集工作。
15. 如何僵尸进程太多,会出现什么问题?
系统中存在大量僵尸进程会耗尽系统可用资源,比如内存、进程ID,降低系统运行效率。还会影响进程管理、导致进程满载,系统无法创建新进程执行新任务、内存泄漏。
16. 如何处理过多的僵尸进程?
- 让父进程使用
wait()或waitpid()等系统调用来回收僵尸进程的资源 - 手动杀死僵尸进程,使用kill命令,指定进程ID杀死僵尸进程。
- 修改子进程的创建方式,避免产生僵尸进程。例如,使用
fork()后紧接着调用exec()或_exit()来替换原始的进程映像,并在父进程中忽略SIGCHLD信号,这样子进程终止时不会成为僵尸进程。
17. 进程的调度算法有哪些?
常见的资源调度算法有:
先来先服务、最短作业优先、优先级调度、轮转调度、多级反馈队列调度、最短剩余时间优先。(我就知道这几个名词)
先来先服务就是哪个进程先到达就执行,适用于短作业时间的场景。也叫非抢占调度算法。
最短作业优先是根据进程的执行时间,选择剩余时间最少得进程优先执行,这样可以减少平均等待时间,但是要准确估计每个进程的的执行时间,不适用于长作业时间的进程。
优先级调度就是为每个进程分配优先级,优先级高的进程先执行。可以根据进程的优先级动态调整调度顺序,但可能会导致低优先级的进程饥饿。
轮转调度是将CPU时间切片分配给每个进程,按照轮转的方式进行调度。每个进程在一个时间片内执行,如果时间片用完,则将进程放到队列尾部继续等待,适用于多任务并发执行。
多级反馈队列调度:将进程根据优先级划分为多个队列,每个队列具有不同的时间片大小。进程根据到达时间和优先级进入对应的队列,并按照轮转调度算法执行。可根据进程的行为和执行情况调整优先级和时间片大小。
最短剩余时间优先(SRTF,Shortest Remaining Time First):类似于最短作业优先算法,但考虑了新进程的到达时间,如果有更短剩余执行时间的进程到达,则抢占当前进程。
18. 进程终止的方式
正常终止、异常终止、人工终止、父进程终止、系统关机。
19. 锁是什么?有哪些常见的锁?
锁是一种用于控制多线程和多进程访问共享资源的同步机制。
锁的基本工作原理是:当一个线程或进程想要访问一个共享资源,它首先会尝试获得锁–如果锁是可用状态(也就是说锁“打开”或者”未锁”),那么该线程或进程会锁住它,然后访问该资源。如果锁不可用(也就是说已经“上锁”或者“被锁定”),则该线程或进程必须等待,直到拥有该锁的线程或进程释放它。
操作系统中常见的两种类型的锁是互斥锁(Mutex)和读写锁(Read-Write Lock):
- 互斥锁:保证同时只有一个线程或进程能够执行某一段临界区的代码。这是最简单,也是最基本的一种锁类型。
- 读写锁:允许多个线程同时读取某一资源,但在写入该资源时只能由一个线程进行。这种锁能提高系统的并发性。
20. 乐观锁和悲观锁有什么区别?
乐观锁和悲观锁是并发控制中两种不同的策略,用于处理多个线程对共享资源的并发访问问题。它们的区别如下:
悲观锁的策略是在访问共享资源之前,假设会发生冲突并进行保护。在悲观锁机制下,如果一个线程要访问共享资源,它会假设其他线程可能会对该资源进行修改,因此会将资源加锁,直到完成操作后才会释放锁。
乐观锁的策略是在访问共享资源时不加锁,而是在更新操作时进行冲突检测。线程在读取共享资源时,不会对其加锁,而是记录下读取时的版本号或其他标识信息。在提交更新操作时,会再次检查共享资源是否被其他线程修改过。如果没有冲突,就执行更新操作;如果有冲突,就放弃当前更新并重新尝试。
性能方面,悲观锁会在访问共享资源之前就加锁,即使没有实际的冲突,也会造成性能的损失。而乐观锁避免了大部分的锁竞争,提高了并发性能。但是,如果冲突频繁发生,乐观锁需要不断地进行重试,可能会导致性能下降。
简单的说 悲观锁和乐观锁是两种不同的并发控制策略。悲观锁假设会有冲突发生,因此在访问共享资源前进行加锁;而乐观锁假设不会有冲突发生,在更新操作时进行冲突检测。
21. 操作系统是如何实现原子操作的?
原子操作指的是不可中断的一个或一系列操作。一旦原子操作开始,就会持续到完成,无法在中间阶段被其他操作打断。
原子操作可以保护共享数据的一致性,防止数据竞态等问题。
22. 什么是死锁?怎么解决死锁?怎么避免死锁?
死锁(Deadlock)是指在多任务环境下,当两个或更多的任务各自拥有一个资源并且等待获取另一个任务持有的资源时,就会发生的一种状态。涉及的任务无法继续执行,因为每个任务都在等待其他任务释放资源,但是没有任务会释放它的资源,因为它们都在等待。这就形成了一个循环的等待状态,从而导致了死锁。
死锁简单的说就是,一个任务在等待另一个任务占用的资源才能释放出资源,另一个任务也在等待这个任务占用的资源才能释放出资源,这样导致两份资源始终释放不出来,两者任务都在干等着,由于资源被锁着释放不了,形成死锁,
死锁就是 多个线程因为争夺资源造成的僵局。
以下是死锁的四个必要条件:
- 互斥条件:一个资源只能由一个任务拥有,在资源释放之前任何其他任务都无法请求到。
- 占有并等待:一个任务持有至少一个资源,但又申请新的资源,而新资源正被别的任务持有,所以申请任务阻塞,但又对自己已获得的资源保持不放。
- 不可抢占:别的任务不能把已获得的资源从任务中强行回收,资源只能由获得它的任务自行释放。
- 循环等待:存在一种可能,即任务之间形成一种任务-资源的环形链,链中每个任务都占有下一个任务所需的资源。
只要这四个条件中的任意一个得不到满足,就不会发生死锁。操作系统的设计者通过算法来破坏这些条件从而避免死锁。例如,可以采用资源按顺序分配策略来避免循环等待,通过设置资源申请超时来避免无限期的资源等待等方法。
解决死锁,解除死锁。解除已经发生的死锁,就是要释放出部分资源。
解除死锁有资源抢占、回滚、进程终止
资源抢占:可以选择部分进程释放出占用的资源,分配给其他进程。
回滚是将部分进程的状态和操作撤销到先前状态,释放出部分资源。
进程终止就是终止部分进程,没有将释放出来的资源手动分配。
死锁的四个必要条件,分别用一两句话概括。
a.互斥条件:每个资源只能被一个线程占有
b.占有和等待:线程在持有一个资源的同时,等待获取其他的资源
C.不可抢占:线程所获取的资源在未使用完毕前,不能被其他的线程抢占
d.循环等待:多个线程形成一种头尾相接循环等待的资源关系
如何避免(预防)死锁。
a.按序申请资源,确保所有的线程在获取多个锁时是按照顺序的
b.减少锁的范围,将锁的力度尽可能的缩小,减少持有锁的时间
c.使用尝试锁的机制,使用Reentrantlock的tryLock的方法,尝试在一段时间内获取锁,如果无法获取选择放弃或者选择其他的方式,避免死锁
d.设置等待超时时间,防止无限制的的等待
e.避免锁嵌套,尽量避免在一个锁的代码块中尝试获取其他锁。
死锁产生的原因有 竞争资源、进程间推进顺序非法。
23. 什么是物理地址?什么是逻辑地址?
物理地址就是实际地址或者绝对地址,是数据在物理内存中的实际位置或者地址。
物理地址是数据真正存储的地方,逻辑地址经过内存管理单元的地址转换后可以得到物理地址。
逻辑地址,也叫虚拟地址,是程序或者进程给我们看到的地址,有CPU生成。对于程序来说,它只需要对内存进行抽象的、逻辑的操作,不用关心具体数据在底层物理内存中的位置。这就是为什么操作系统需要引入逻辑地址的原因。
24. 什么是虚拟内存?为什么需要虚拟内存?
虚拟内存不是实际的物理内存,操作系统将实际内存和磁盘空间组合使用,给每个进程提供一个非真实、看似连续的地址空间。
虚拟内存可以使得操作系统为每个进程提供独立的地址空间,使进程之间相互隔离。同时虚拟内存提供了一种内存扩展的能力,使系统能够运行更多的程序,避免因为物理内存不足而导致程序崩溃。
虚拟内存可以扩展可用内存,让系统运行更多程序。可以实现进程隔离和保护。虚拟内存不关心实际的物理内存,简化了内存管理,而且虚拟内存允许多个进程共享同一部分内存,实现进程间的通信。
25. 什么是栈空间?什么是堆空间?栈空间和堆空间有什么区别?
栈空间就是实现后进先出数据结构的内存空间,常见就是递归代码涉及栈帧。
堆空间是计算机分配了一段内存区域,用来存储程序运行过程中动态分配的数据。当程序需要一块动态内存时,程序会向操作系统发出请求。操作系统如果同意了这个请求,会在堆上找到一块合适的空闲空间,然后将其分配给程序。程序用完这块内存后,需要显式地将其释放,否则会造成内存泄露。
比如我们要创建一个数组,你可能无法预先知道数组的大小,这时候你就需要在堆上动态地创建这个数组。因为在栈上创建数组需要预先知道其大小,且在函数体结束后会自动释放。
和栈空间相比,堆空间的大小不是在编译时确定的,而是在运行时通过程序的需求动态分配的。我们可以在运行时根据需要创建和销毁数据。
区别:
一般上如果需要生命周期短,大小已知的数据,应该使用栈;如果你需要能够动态分配,生命周期可控的数据,应该使用堆。
- 存储内容:栈主要存储局部变量和函数调用的信息,比如函数的返回地址和参数。堆被用来存储动态分配的数据,例如动态数组,对象,或者其他需要在程序运行中根据需要动态创建和销毁的数据。
- 生命周期:栈空间中的数据在定义它们的函数返回之后就会自动销毁,生命周期较短。而堆上的数据需要程序显式地创建和销毁,因此它们的生命周期可以被精确地控制,但同时也使内存管理变得更加复杂。
- 分配方式:栈空间是由编译器自动分配和释放的,非常快速。但是,堆空间是由程序在运行时动态分配和释放的,这通常需要更多的计算资源。
- 大小限制:栈空间的大小通常在程序启动时就被固定,所以它的空间通常比较小。而堆的大小通由系统的可用内存来决定,所以它的空间通常比较大。
- 优点和缺点:
栈空间的优点是管理简单,速度快。但它的缺点是空间有限,不能动态分配,只能用于存储生命周期短且大小已知的数据。
堆空间的优点是能够动态地分配大量的内存。但是它的缺点是需要手动管理,可能会引发内存泄漏或碎片,而且开销较大。
26. 分页与分段有什么区别?
分页和分段都是内存管理的策略。
分页是将虚拟内存空间和物理内存空间分割成固定大小的单元,我们称这个单元为”页”。分页是为了解决内存碎片的问题,因为分页可以让每一块内存空间都被有效利用。分页是透明的,也就是说这个过程对用户程序是不可见的。用户程序看到的仍然是一个连续的内存空间。
分段是将程序自身的逻辑结构反映到物理存储器中去。在逻辑上,程序员根据代码的逻辑关系将程序分成大小不等的段,比如说代码段、数据段等。然后根据程序的需要,将这些段加载到内存中。 分段是可见的,也就是说程序员在编写程序的时候可以看到分段的效果。
主要区别在于:
- 目的: 分段是为了反映程序的逻辑结构,分页是为了更有效地使用内存,并减少内存碎片。
- 大小:页的大小是固定的,机器系统决定了页的大小,且各个系统的页面大小不一样。段的大小是可变的,由程序的逻辑结构决定。
- 可见性:用户程序可以看到分段的结果,但是看不到分页的结果。
在实际的系统中,分页和分段往往并用,这种技术被称为段页式管理。
27. 页面置换算法有哪些?页面置换算法是用来干嘛的?
页面置换算法常见的有四种:
最佳页面置换、最近最少使用、先进先出、Clock。
页面置换算法是为了当内存满了时候,选择置换出哪个页面来为新页面提供空间。
28. 什么是动态链接库?
动态链接库一种在程序运行时,而不是在程序编译时,被加载进内存的库。意味着一些代码可以被多个程序同时使用,而不需每个程序都有一份自己的代码拷贝。这样可以节省内存资源和硬盘空间,并且使得程序升级和修改变得更为简单,只需替换底层的 DLL 文件即可。
29. 动态链接和静态链接有什么区别?
静态链接:
静态链接是在编译时,所有的库函数都会被链接到应用程序中,形成一个完整独立的可执行文件。因此,静态链接生成的程序在执行时不再需要其他的库文件,可以在任何环境中运行。
优点:
- 生成的可执行文件通常对环境没有任何依赖,安全可靠,部署方便。
缺点:
- 所生成的可执行文件通常比动态链接的可执行文件大很多,因为所有使用到的库代码都被嵌入进了可执行文件。
- 无法利用系统已装载的库代码,必须在每个程序中都包含一份库代码的拷贝,浪费内存。
- 当库函数有更新时,需要重新编译链接应用程序,否则无法使用新版本的函数。
动态链接:
动态链接是只在编译时确定程序的全部功能,但并不把库函数添加到程序中,而是在程序运行时由操作系统负责加载库函数,如果需要用到某个库函数,程序只需要在需要的时候动态的链接库函数。
优点:
- 可执行文件小,节省磁盘空间,因为它只需要包含创建和管理动态链接所必需的少量信息。
- 可以更好地共享代码和数据。同一时间,多个应用程序可以使用单个内存中的库副本。
- 当库函数有更新时,只需替换动态库,所有使用到的应用程序都可以利用到新的功能,无需重新链接。
缺点:
- 需要保证运行环境中有所需的库文件,否则程序将无法运行。
- 运行速度可能稍慢,因为程序需要在运行时进行链接。
- 存在版本兼容性问题。不同版本的库文件可能存在不兼容性,可能会引起程序错误或崩溃。
打包全部、一个还需要其他提供能力。
30. 什么是中断?中断和异常的区别?什么是软中断,什么是硬中断
中断就是计算机会中断程序的正常运行,就是计算机在运行过程中,由于内部或者外部因素,比如硬件故障、IO请求、定时器事件等,这些事件需要在合适的时机中断正常的程序执行。
中断的作用是为了打断当前的程序执行流程,转而执行与中断事件相关的处理程序。处理程序执行完毕后,再返回到原来的程序继续执行。中断可以实现多任务的并发执行,提高系统的响应能力和效率。
中断可以分为硬件中断和软件中断。硬件中断是由硬件设备触发的,比如外部设备的请求、时钟中断等。软件中断是由软件程序主动触发的,比如系统调用、异常处理等。
软中断的优先级一般低于硬中断。
中断更多地涉及到硬件,是一种异步的情况,它允许处理器响应外部的实时事件。异常更多地涉及到软件,它提供了一种机制来处理程序运行中的错误或者异常情况。
31. 一个程序从开始运行到结束的完整过程,简要陈述一下?
一个程序从开始运行到结束的完整过程可以概括如下:
- 编写程序:程序员根据需求和规范,使用编程语言编写程序代码。
- 编译/解释:根据程序的编写语言,将程序源代码转化为机器可执行的形式。对于编译型语言,程序需要通过编译器将源代码编译成机器代码;对于解释型语言,程序会逐行解释执行。
- 加载:操作系统将编译/解释后的程序加载到内存中,为运行做准备。加载过程中会分配所需的内存空间,并进行一些初始设置。
- 运行:程序开始执行,通常从程序的入口点开始,在操作系统的调度下,逐行执行程序代码。
- 数据处理:程序根据算法和逻辑对数据进行操作,进行计算、判断、循环等各种处理过程。
- IO操作:程序可能需要与外设交互,进行输入输出操作。如文件读写、网络通信、用户交互等。
- 异常处理:在程序运行过程中,可能会出现各种异常情况,包括错误、异常输入、资源不足等。程序需要进行适当的异常处理,避免程序崩溃或数据丢失。
- 结束运行:程序执行到结束点,或者通过某种条件判断需要提前结束,程序会执行相应的结束操作。资源会被释放,可能会输出一些结果或保存数据。
- 卸载:程序运行结束后,操作系统会将程序卸载,释放相关资源。
需要注意的是,不同的操作系统和编程环境可能在具体的实现上有所差异,但整个过程的基本流程是类似的。
32. 什么是内存泄漏?
内存泄漏是程序无法释放已经不再使用的内存的情况。
33. 内存泄漏和内存溢出有什么区别?
内存泄漏(Memory leak)和内存溢出(Memory overflow)是两种不同的内存管理问题,它们的区别如下:
- 内存泄漏:内存泄漏指的是程序在动态分配内存后,未能正确释放已经不再需要的内存,导致这部分内存无法再被程序使用,最终导致系统内存的浪费。内存泄漏会导致系统运行时的内存消耗逐渐增加,最终耗尽系统的可用内存。
- 内存溢出:内存溢出指的是程序在运行过程中,申请的内存超过了系统实际可用的内存大小。当程序申请内存无法得到满足时,会出现内存溢出的错误。内存溢出可能导致程序异常终止、系统崩溃或无法响应。
- 引发原因:内存泄漏通常是由程序中未正确释放内存的错误操作引起的,例如忘记调用释放内存的函数、指针引用不正确等。而内存溢出通常是由程序在执行过程中,动态申请的内存超过了系统的限制,尤其在递归函数调用、无限循环等情况下更容易发生。
- 影响范围:内存泄漏只会影响程序本身,逐渐占用系统内存,导致程序性能下降甚至崩溃。而内存溢出是系统级的问题,可能会影响其他正在运行的程序,导致整个系统崩溃。
- 调试和解决:内存泄漏通过内存分析工具和代码分析来发现和解决,需要找到未释放内存的位置并进行修复。内存溢出的处理较为困难,通常需要优化算法和数据结构,减少内存的占用,并确保程序在申请内存前通过判断来避免申请超出系统限制的内存。
总之,内存泄漏和内存溢出是两种不同的内存管理问题。内存泄漏是指未正确释放不再使用的内存,导致系统内存的浪费;而内存溢出是指申请的内存超过了系统可用内存大小,可能导致程序崩溃或无法响应。
34. 内存交换中,被换出的进程保存在哪里?
保存在 磁盘上的交换区 中。
交换区是一个用于临时存储被换出进程的磁盘空间。当系统内存不足时,操作系统会将一部分暂时不活跃或者优先级较低的进程页面(Page)或进程块(Process Block)换出到交换区,以释放内存空间供其他活跃进程使用。被换出的进程在交换区中以某种形式存储,并在需要时可以被换入(Swapping in)到内存中重新运行。
页面置换算法?
需要注意的是,由于磁盘
的访问速度相对较慢,当进程被换出到交换区后,重新换入内存时可能会引起较大的延迟。因此,系统在进行内存交换时需要权衡内存和磁盘的访问效率,以及进程的运行性能。
35. 原子操作的是如何实现的
处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。
36. 抖动你知道是什么吗?
操作系统的抖动是指频繁的换页(页面交换)。就是当系统的内存资源不足时,系统进行频繁的页面置换,系统花费过多的时间在读取或写入磁盘空间,而不是执行实际的工作,影响性能。
37. CPU使用率和CPU负载指的是什么?它们之间有什么关系?
CPU使用率:是指在特定时间窗口内,CPU用于处理任务的时间百分比(例如,使用率70%表示CPU70%的时间在运行用户进程或内核任务,30%的时间空闲)。
使用率通常细分为:
用户态时间(user time):运行用户进程的时间.
内核态时间(system time):运行系统调用或内核任务的时间。
空闲时间(idle time):CPU无任务可执行时的时间。
CPU负载:CPU负载表示系统中需要被CPU处理的任务数量(包括运行队列中的任务和等待CPU时间片的任务,常用指标:1分钟、5分钟、15分钟的平均负载)。
负载值解读:
·小于等于CPU核心数:系统任务通常能被及时处理,性能较好。
·大于CPU核心数:系统可能出现任务排队,性能下降。
两者之间的关系
CPU使用率和负载均与系统任务量相关,但含义不同:
·CPU使用率反映CPU工作的忙碌程度。
·CPU负载反映等待处理的任务数量( 不仅包括CPU繁忙任务,还包括I/O等待的任务)。
常见可能的组合:
·高使用率,高负载:CPU任务超负荷,系统性能瓶颈可能在计算能力。
·低使用率,高负载:可能存在大量/O密集型任务或锁竞争。
·高使用率,低负载:CPU忙碌,但任务调度良好。
·低使用率,低负载:系统空闲,资源未被充分利用。
38. 常见的Linux命令。
ls、cd、mkdir、rm、cat、ps、kill、ping、ifconfig/ip、sudo
39. I/O是什么?
IO就是输入输出,指的是计算机和外部设备之间的数据传输机制。
40. I/O模型有哪些?
常见的IO模型有:
阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO
41. 为什么网络I/O会被阻塞?
网络/O会被阻塞是因为在进行网络数据传输时,操作系统在等待数据的发送或接收完成之前,会将进程挂起,直到数据传输完成后才恢复进程执行。
阻塞的主要原因是:
- 等待数据到达或发送完成:当进程尝试从网络套接字中读取数据时,如果数据尚未到达,操作系统会使进程进入阻塞状态,直到数据到达为止。同样,当数据未能立即发送出去时,发送操作也可能被阻塞,等待缓冲区有空闲空间。
- 系统资源有限:当系统资源(如网络缓冲区、连接数等)被占满时,进一步的I/O请求可能会被阻塞,等待资源释放后才能继续。
- 默认的阻塞行为:大多数网络API(如recv、send、accept等)在默认情况下都是阻塞的,即调用这些API时,如果条件不满足,会使调用者等待,到I/O操作完成。
42. 负数的二进制如何表示?
用 补码 表示。