零拷贝是什么
sendfile 可以避免这个用户态和内核态的频繁切换
redis ,nginx,netty 是依赖什么做的这么高性能?
主要是依赖Reactor 模式 ,这里指的就是反应堆模式,就是对事件反应,也就是来了一个事件,Reactor 就有对应的反应/响应,Reacto模式主要由Reactor 和处理资源池这两个核心部分组成, Reactor 负责监听和分发事件,事件类型包括连接事件,读写事件; 处理资源池负责处理事件,如 read-> 业务逻辑-> send
用户态和内核态有什么区别?
用户态和内核态是 CPU 的两种运行级别,区别在于权限:内核态可以执行所有指令、访问所有硬件和内存;用户态只能执行普通指令,不能直接操作硬件。在 x86 架构上,它们分别对应特权级 Ring 0 和 Ring 3。
两种状态的区别
| 对比项 | 用户态 | 内核态 |
|---|---|---|
| 运行的代码 | 普通应用程序 | 操作系统内核 |
| 指令权限 | 只能执行非特权指令 | 可执行全部指令,包括特权指令 |
| 访问资源 | 不能直接访问硬件和内核内存 | 可访问所有硬件和内存 |
| 出错影响 | 通常只影响当前进程 | 可能导致整个系统崩溃 |
内核态负责的核心工作包括:进程调度、内存管理、文件系统、设备驱动、网络协议栈等。
为什么要划分两种状态
- 安全:应用程序不能随意读写硬件或其他进程的内存,恶意或有缺陷的程序无法直接破坏系统。
- 稳定:用户程序崩溃只影响自身,不会拖垮整个操作系统。
- 隔离与可维护:内核与应用之间有清晰的边界,应用只能通过规定的接口使用系统服务,便于模块化设计。
如何从用户态进入内核态
主要有三种途径:
- 系统调用:程序主动请求内核服务,如
read、write、open、fork。这是最常见的方式。 - 异常:程序执行出错,如缺页、除零,CPU 自动切到内核处理。
- 外部中断:硬件设备发出信号,如磁盘读写完成、网卡收到数据、时钟中断。
以读文件为例:
c
char buf[1024];
int fd = open("data.txt", O_RDONLY); // 系统调用,陷入内核
read(fd, buf, sizeof(buf)); // 内核从磁盘读数据,拷贝到用户缓冲区切换的开销
每次切换都要保存和恢复寄存器、切换栈,还可能影响 CPU 缓存和 TLB,因此频繁切换会降低性能。很多高性能技术正是为了减少切换和数据拷贝:
- 零拷贝(
sendfile、mmap):减少用户态与内核态之间的数据复制。 - IO 多路复用(
epoll):一次系统调用监听大量连接。 - 用户态协程:在用户态完成调度,避免线程切换陷入内核。
总结
用户态与内核态的划分是操作系统安全和稳定的基础。应用程序通过系统调用、异常、中断进入内核态,切换有一定开销,这也是零拷贝、epoll 等优化手段存在的原因。
📮 联系方式
微信:BuZhiCoder | QQ:1776418445 扫码添加,备注「求职」优先通过
