文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
什么是用户态和内核态
用户态和内核态是操作系统的两种运行状态。
内核态
:
- 处于内核态的 CPU 可以访问任意的数据,包括外围设备
- 比如网卡、硬盘等,处于内核态的
CPU
可以从一个程序切换到另外一个程序
- 并且占用 CPU 不会发生抢占情况,一般处于特权级 0 的状态我们称之为内核态。
用户态
:
- 处于用户态的 CPU 只能受限的访问内存,并且不允许访问外围设备
- 用户态下的 CPU 不允许独占,也就是说 CPU 能够被其他程序获取。
那么为什么要有用户态和内核态呢?
- 这个主要是访问能力的限制的考量,计算机中有一些比较危险的操作
- 比如设置时钟、内存清理,这些都需要在内核态下完成
- 如果随意进行这些操作,那你的系统得崩溃多少次。
为什么要区分用户态和内核态呢?
在操作系统中,用户态(
User Mode
)和内核态(Kernel Mode
)是两种不同的执行状态。这种区分主要是为了保障操作系统的稳定性,安全性以及提高效率。
以下是这种区分存在的几个主要理由:
保护操作系统及关键内核数据:
- 在内核态,操作系统代码有权访问系统的所有资源
- 而在用户态,应用程序的活动受到限制,不能直接访问硬件或内核数据结构
- 所有涉及硬件操作的请求都必须通过内核代码(例如设备驱动程序)来完成。
- 这种限制可以避免用户态的应用程序意外或恶意地破坏系统资源。
安全性:
- 用户态和内核态的划分是操作系统进行权限管理和访问控制的主要方式
- 它可以防止用户级应用程序越权访问和操作系统资源,提高系统的安全性。
系统稳定性:
- 如果所有程序都在同一权限级别运行,一个程序的错误可能导致整个系统崩溃。
- 通过将权限划分为用户态和内核态,可以有效地防止用户程序的错误影响到整个系统,提高系统的稳定性。
效率:
- 内核态与用户态的切换会带来一定的开销,但这背后的好处是系统运行的效率和稳定性。
- 例如,IO操作通常需要在内核态进行,以防止用户程序直接控制硬件设备
- 这样可以防止多个程序同时对一个设备进行操作,引起混乱。
因此,划分用户态和内核态,为操作系统的运行提供了一个有序、可控和安全的环境。
谈一谈你对中断的理解?
中断是计算机系统中的一种基本操作,用于处理外部事件或内部异常。
- 在计算机运行过程中,可能会发生各种外部或内部的事件,比如硬件故障、IO请求、定时器事件等
- 这些事件需要在合适的时机中断正常的程序执行。
中断的作用是打断当前的程序执行流程,转而执行与中断事件相关的处理程序。
- 处理程序执行完毕后,再返回到原来的程序继续执行。
- 中断可以实现多任务的并发执行,提高系统的响应能力和效率。
中断可以分为硬件中断和软件中断。硬件中断是由硬件设备触发的,比如外部设备的请求、时钟中断等。
- 软件中断是由软件程序主动触发的,比如系统调用、异常处理等。
中断和异常有什么区别?
中断(
Interrupt
)和异常(Exception
)都是在计算机运行过程中对特殊的条件或者事件的响应
- 但是它们之间还是有一些明确的区别的。
触发条件:
中断通常是由外部事务触发的,如用户输入、外设请求等。
- 这些事件不一定与当前执行的程序有关。
- 而异常通常是由程序本身在运行过程中产生的,比如除零错误、非法指令等。
处理方式:
- 中断的处理通常是将当前的程序执行指针保存起来,然后切换到中断处理程序去执行,处理完后返回原来指针处继续执行。
- 而异常处理则需要首先确定是不是可以恢复的错误,如果可以恢复,那么在处理完成后可以从出错的地方继续执行
- 如果不可恢复,那么可能需要终止程序。
终止与持续:
- 一般来说,处理完中断后,CPU会恢复执行被中断的程序,而异常可能会导致程序的终止。
预期性:
- 中断是可以被预期且常规的行为。
- 例如,系统可以预期硬件设备的中断,并根据这些中断进行响应。
- 然而异常则是非预期的,它们是因为程序错误、硬件问题或其他不可预料的条件产生的。
指向性:
- 中断指向的是特定的中断服务程序,而异常指向的是错误处理程序或者是系统。
什么是栈空间?
栈是一种后进先出(LIFO)的数据结构,也就是说最后进入的元素会被首先取出。
- 每当一个函数被调用时,系统会为其在栈空间上分配一块内存,这个内存区域被叫做一个栈帧。
- 这个栈帧将存储这个函数需要用到的局部变量,参数,以及函数返回的地址。
当函数执行结束后,对应的栈帧就会被释放,相关的存储空间将供后续的函数调用使用。
- 由于栈使用类似于压栈和出栈的操作,所以速度很快,但是容量有限
- 过深的函数调用或者递归可能导致栈空间耗尽,这就是常说的栈溢出。
例如,你可能会写一段递归代码来解决问题。
每次调用这段代码的一个新实例时,都会有一个新的栈帧被创建以存储这次调用的信息。
- 无限或过深的递归可能会导致栈空间耗尽,导致所谓的 栈溢出 错误。
什么是堆空间?
堆空间它用来存储程序运行过程中动态分配的数据。
- 与栈空间不同,堆空间的大小不是在编译时确定的,而是在运行时通过程序的需求动态分配的。
- 这就意味着你可以在运行时根据需要创建和销毁数据。
当程序需要一块动态内存时,程序会向操作系统发出请求。
操作系统如果同意了这个请求,会在堆上找到一块合适的空闲空间,然后将其分配给程序。
- 程序用完这块内存后,需要显式地将其释放,否则会造成内存泄露。
举个例子,如果你需要根据用户输入创建一个数组,你可能无法预先知道数组的大小
这时候你就需要在堆上动态地创建这个数组。
因为在栈上创建数组需要预先知道其大小,且在函数体结束后会自动释放。
但是,堆空间的管理相对复杂。动态分配和释放内存需要更多的计算资源
- 因为操作系统需要查找可用的空闲空间,且可能出现内存碎片问题。
另外,由于程序员通常需要在程序中显式管理堆内存
- 所以还可能出现内存泄漏(忘记释放不再需要的内存)或者是野指针(指向已经释放的内存)等问题。