用户态与内核态:权限与地盘的秘密

内核态、用户态本质就是:权限不一样、地盘不一样。

一句话总结

  • 用户态(User Mode):应用程序跑的地方,权限极低,不能乱搞硬件、不能乱改内存。
  • 内核态(Kernel Mode):操作系统内核跑的地方,最高权限,想干嘛干嘛(管 CPU、内存、网卡、磁盘…)

1. 为什么要分这两个态?

为了安全 + 稳定。如果随便一个 APP 都能直接操作硬件、改内存,那:

  • 一个程序崩溃 → 整机死机
  • 病毒随便读写硬盘、网卡
  • 多个程序互相踩内存

所以操作系统画了一条红线

  • 应用:只能在自己小圈子里玩
  • 内核:掌管一切,只信任自己

2. 权限差别(最核心)

用户态(受限模式)

  • 不能直接访问硬件(网卡、硬盘、键盘…)
  • 不能访问其他进程的内存
  • 不能修改系统配置
  • 崩溃了最多自己挂掉,不影响系统

内核态(最高特权模式)

  • 可以直接读写所有内存
  • 直接控制硬件(网卡收发包、写磁盘)
  • 管理进程、调度 CPU
  • 内核崩溃 =整个系统卡死 / 蓝屏

3. 内存上的划分(直观理解)

操作系统把虚拟内存切成两部分:

  • 低地址 → 用户态空间你的 QQ、浏览器、Nginx、Java 进程都在这
  • 高地址 → 内核态空间整个系统只有一份,所有进程共享但不能随便碰
┌─────────────┐ 高地址 │ 内核空间 │ ← 内核态才能访问 │ (共享) │ ├─────────────┤ │ │ │ 用户空间 │ ← 每个进程独立,互相看不见 │ │ └─────────────┘ 低地址

一个进程不能直接跨过这条线读写数据。


4. 什么时候切换?系统调用

应用想干 “越权” 的事,必须发请求让内核代劳,这个过程叫:

系统调用(syscall)比如:

  • 读文件
  • 发网络包
  • 分配大块内存
  • 打印到屏幕

流程:

  1. 用户态程序:read()/write()/recv()
  2. CPU 切换到内核态
  3. 内核帮你完成操作
  4. 切回用户态,把结果还给你

这个切换是有开销的,所以高性能网络会尽量减少切换。


5. 结合网络收包流程

把 “内核态 / 用户态” 标进去就一目了然:

网卡收到包 → 内核态处理(硬中断、软中断、协议栈) → 放到 socket 队列(依然在内核态) → 应用调用 recv() → 切换内核态 → 内核把数据从内核空间 → 拷贝到用户空间 → 切回用户态,应用拿到数据

关键点:

  • 收包全过程,前半段全在内核态
  • 应用真正拿到数据,才是用户态
  • 中间那次拷贝 + 状态切换,是传统网络性能的一大瓶颈

超简记忆版

  • 用户态:应用程序,小弟,权限小,安全
  • 内核态:操作系统内核,大哥,权限大,危险
  • 系统调用:小弟找大哥帮忙,必须切换身份