现代计算机系统中,所有的硬件资源都是由操作系统负责管理的,硬件资源包括 CPU 的使用时间、物理内存的使用、硬盘的读写等等。操作系统内核当然是工作在内核态下,普通的用户进程工作在用户态下。
处于内核态的操作系统内核对于硬件有不受限制的使用权限,并且可以执行任何 CPU 指令以及访问任意的内存地址。
而用户态进程没有能力直接操作硬件,也没有能力访问任意的内存地址空间。用户态进程只能通过操作系统内核提供的系统调用受限地使用硬件资源。并且用户态进程不能执行一些 CPU 特权指令。
系统调用属于内核空间代码,而用户态进程运行在用户态,所以执行系统调用时,程序的执行流程要从用户态切换到内核态。早期 Linux 通过中断的方式实现系统调用,中断号为 0x80。从用户态切换到内核态的代价是,首先要进行现场保护,即保存当前用户态的状态,以便执行完系统调用后恢复;其次是要从用户堆栈切换到内核堆栈;接着执行 0x80 号中断对应的中断处理程序,再通过中断处理程序找到相应的系统调用代码。系统调用执行完毕后又要切换堆栈、恢复现场。
新的 CPU 提供了专门用于系统调用的 sysenter 和 sysexit 指令,使得系统调用的执行速度更快更高效。
1.首先内核态和用户态的堆和栈是不一样的,所以必然会发生寄存器状态的切换,其实单纯切换寄存器影响倒不是特别大,大概就是会影响 CPU 方面的一些比如指令流水,分支预测等
最大的问题是用户态程序发生系统调用相当于把控制权交给内核,内核甚至会剥夺当前进程的执行,去执行另一个进程,那这个时候要发生 TLB flush,这个对性能影响非常大不说,整个进程的执行都会停止
2.区别是代码执行的层级;性能损失来源于缓冲区的复制。