HowLinuxWorks随记
这本书讲 Linux 的骨架:内核、进程、内存、文件系统、命令行。我读的时候最有用的不是记住每条命令,而是搞清楚”敲一条命令时,系统里发生了什么”。这篇记录我留下的部分。
三层结构
Linux 分为三层:用户进程、内核、硬件。
内核在硬件之上,管理硬件,是硬件系统和应用程序之间通信的接口。
进程指计算机中运行的所有程序,组成最顶层,叫做用户空间(user space)。
用户进程和内核最根本的区别:内核运行在内核模式(kernel mode),用户进程运行在用户模式。内核模式下不受限制,可以访问处理器和内存的任何部分。只有内核能访问的空间叫内核空间(kernel space),用户进程能访问的叫用户空间。一般来说,用户进程的影响范围被限制在用户空间内。
内核在管四件事
- 进程:决定哪个进程可以使用 CPU
- 内存:内存分配,管理进程间的共享内存与空闲内存
- 设备驱动程序:硬件系统和进程之间的接口
- 系统调用和支持:进程通过系统调用和内核通信
进程管理:上下文切换
CPU 同时运行多个进程,靠的是轮流执行,叫多任务执行。CPU 从一个进程切换到另一个进程,叫上下文切换(context switch)。完整过程:
- CPU 停止 A 进程,由内核接管 CPU 控制权
- 内核记录当前 CPU 和内存的状态信息,恢复进程时使用
- 内核执行上个时间段内被挂起的任务(输入输出、磁盘读写)
- 内核从准备就绪的进程中选择下一个
- 内核为 B 进程准备 CPU 与内存
- 内核把新进程的执行时间段通知 CPU
- 内核将 CPU 切换至用户模式,把控制权移交给新进程
内核在什么时候运行?在上下文切换的时间段间隙中运行。
内存管理:MMU 和页表
内核在上下文切换过程中管理内存,要保证:
- 内核自己的专有内存空间
- 每个用户进程的专有空间
- 用户进程之间的共享空间
- 某些用户进程的内存空间是只读的
- 交换空间(swap space):用磁盘扩展出比物理内存更大的可用空间
进程不直接访问物理内存。MMU(内存管理单元)截获进程的访问请求,通过内存映射表把虚拟地址转换成实际物理地址。这张表由内核维护,用页表(page table)实现。
系统调用:fork 和 exec
有些事用户进程自己做不了,比如打开、读取、写文件,这些操作都要通过系统调用(system call)请内核完成。
两个最基础的调用:
fork():内核创建一个和当前进程几乎一样的副本exec(program):内核启动 program 来替换当前进程
除了 init,Linux 里所有用户进程都是通过 fork() 启动的。多数情况下,你还可以用 exec() 启动新进程。
在终端输入 ls 时发生的事:shell 调用 fork() 创建一个 shell 副本,这时候有了两个一样的 shell 进程,然后副本调用 exec(ls) 来运行 ls。
内核还提供虚拟设备,比如随机数生成器(/dev/random)。它技术上不一定要放在内核里,但实现难度上,放在内核里要小得多。
用户
Linux 继承了 UNIX 的用户概念。早期还没有 PC 这个概念时,一台设备接多个终端,多个用户共用。
内核用用户 ID 管理用户,每个用户进程都有一个所有者。管理员用户即 root,拥有超级权限。
root 权限很高,但 root 也运行在用户模式,不是内核模式。
命令行的背后
Linux 默认 shell 是最初 Bourne Shell 的增强版,叫 bash(Bourne-again shell)。
标准输入输出
进程从输入流读数据,向输出流写数据。
终端里只输入 cat,cat 就从标准输入流读数据,运行 cat 的终端就成了标准输入。这时候你输入任意字符都会回显。
Ctrl+D 终止当前终端的标准输入并结束命令;Ctrl+C 终止进程本身,不管有没有输入输出。
标准输出同理。cat 运行时标准输出和终端建立连接,所以能看到回显。
标准输入和标准输出简写为 stdin 和 stdout。很多命令和 cat 一样,不指定输入文件就从标准输入读。输出则有些命令会直接写到文件。
通配符展开
shell 中 * 代表任意字符和数字。Shell 根据通配符匹配文件,把命令中的参数替换成实际的文件名,这个过程叫展开:
at*展开为所有以 at 开头的文件名*at展开为所有以 at 结尾的文件名*at*展开为所有包含 at 的文件名
? 匹配任意一个字符,比如 b?at 匹配 boat 和 brat。
如果没有匹配的文件名,shell 就不展开。
不想展开可以用引号包起来:'*'。
Linux 中 . 代表当前目录(./mydir/),.. 代表上级目录(cd ../../usr)。
常用命令
1 | 打印 |
环境变量和 PATH
通过 $ 使用声明过的变量。
环境变量和 Shell 变量的区别:Shell 变量只能被当前 shell 使用,export 后变成环境变量,可以传给子进程。
1 | STUFF=blah |
PATH 决定你在任意目录敲命令时,shell 去哪里找可执行文件。把目录加进 PATH:
1 | PATH=$PATH:dir |
命令行编辑
一些比箭头更好用的快捷键:
1 | Ctrl+B 左移 |
目录结构
/bin:基础命令的可执行文件,大部分是 C 编译器创建的二进制文件/dev:设备文件/etc:系统配置文件/home:个人目录/lib:可执行文件使用的代码库/proc:当前运行的进程和内核信息/sys:类似 /proc,暴露内核与硬件信息/sbin:系统管理命令,很多需要 root 运行/tmp:临时文件,很多系统启动时会清空/usr:存放许多 Linux 系统文件/var:运行时数据,如系统日志、用户信息、缓存
命令背不下来没关系,用到再查。搞清楚命令背后谁在干活,比记住命令本身有用。




