我的知识记录:操作系统

技术学习笔记

Posted by yZhang on April 18, 2025

1.进程线程和协程

1.1 垂直包含关系

进程(容器层) → 线程(执行层) → 协程(任务层)

  • 进程 是资源分配的顶层单位,为程序提供独立的内存、文件等隔离环境;是操作系统中进行资源分配和调度的基本单位。
    • 每个进程至少包含 1个主线程
    • 示例:浏览器中每个标签页是独立进程,崩溃互不影响。
  • 线程 是CPU调度的基本单位,共享进程内的资源(内存、文件等);它是进程内的一个执行单元,也是CPU调度和分配的基本单位。
    • 1个进程可包含 多个线程(如Chrome的渲染线程、网络线程)。
    • 示例:视频编辑软件用多线程并行处理不同轨道的渲染。
  • 协程 是用户态轻量级线程,寄生在线程中,由程序自行调度;其调度完全由用户程序控制,而不需要内核的参与。
    • 1个线程可调度 成千上万个协程(如Go的goroutine)。
    • 示例:Web服务器用协程同时处理数万个HTTP连接。

类比

  • 进程 = 工厂(独立厂房和原料仓库)
  • 线程 = 生产线(共享厂房,多条线并行)
  • 协程 = 工人(在一条生产线上快速切换任务)

1.2 协作场景示例(Web服务器架构)

1
2
3
4
5
6
7
8
        [主进程](守护进程)
           │
   ┌───────┴───────┐
[子进程A]       [子进程B]  ← 隔离用户A/B会话
   │               │
[线程池]         [线程池]  ← 每个进程4线程(4核CPU)
   │               │
[协程群]         [协程群]  ← 每线程处理1万个连接
  • 进程级隔离:防止单个用户请求崩溃导致服务全局瘫痪。
  • 线程级并行:利用多核CPU执行压缩/加密等计算任务。
  • 协程级并发:用极低开销管理海量I/O操作(如数据库查询)。

1.3 三者的本质区别

维度 进程 线程 协程
资源 独立内存/文件 共享进程内存 共享线程栈
切换 需内核介入(开销大) 需内核介入(开销中) 用户态切换(开销极小)
崩溃 不影响其他进程 可能导致进程崩溃 仅影响当前协程

关键结论

  • 包含性:进程 ⊃ 线程 ⊃ 协程
  • 协作性:三者共同实现 安全隔离(进程)、硬件利用(线程)、高并发(协程)。

1.4 线程切换、

1.5 进程状态、上下文、通讯和调度

1.6 其他问题

2.Lunix常用命令合集

Lunix如何查看进程号状态?

1
2
3
4
5
6
7
8
# a:显示所有用户的进程。
# u:展示详细的用户信息。
# x:显示没有控制终端的进程。
# -e:等同于a,即显示所有进程。
# -f:呈现完整格式的输出。
ps aux       # 显示所有用户的所有进程
ps -ef       # 显示完整格式的进程信息
ps -ef | grep 进程名  # 查找特定进程

Lunix下如何查看网络连接情况?

1
2
3
4
5
# netstat:查看网络连接情况
netstat -anp  # 显示所有网络连接
netstat -tnp  # 显示tcp连接
netstat -tnlp  # 显示tcp连接和监听端口
netstat -s  # 显示网络统计信息

Lunix下如何查看磁盘使用情况?

1
2
# df:查看磁盘使用情况
df -h  # 以可读方式显示磁盘使用情况

Lunix下如何查看内存使用情况?

1
2
# free:查看内存使用情况
free -h  # 以可读方式显示内存使用情况

Lunix下如何查看CPU使用情况?

1
2
# top:查看CPU使用情况
top  # 按1、5、15分钟的平均负载显示CPU使用情况

Lunix下如何查看进程的内存使用情况?

1
2
# pmap:查看进程的内存使用情况
pmap -x 进程号  # 查看进程的内存使用情况

Lunix下如何查看进程的CPU使用情况?

1
2
# pidstat:查看进程的CPU使用情况
pidstat -u 1  # 显示每秒的CPU使用情况

Lunix下如何查看进程的IO使用情况?

1
2
3
# iostat:查看进程的IO使用情况
iostat -d 1  # 显示每秒的磁盘IO使用情况
iostat -x 1  # 显示每秒的磁盘IO使用情况,包括系统调用

Lunix下如何查看进程的网络使用情况?

1
2
# iftop:查看进程的网络使用情况
iftop -t  # 显示每秒的网络IO使用情况

Lunix下如何查看进程的线程数?

1
2
# pstree:查看进程的线程数
pstree -p 进程号  # 查看进程的线程数

3.操作系统的内存管理

3.1 虚拟内存

操作系统设计了虚拟内存,每个进程都有自己的独立虚拟内存,我们写的程序不会直接与物理内存打交道;虚拟内存是操作系统提供给每个运行中程序的一种地址空间,每个程序在运行时认为自己拥有的内存空间就是虚拟内存。
虚拟内存通过将程序的地址空间划分为若干个固定大小的页或段,并将这些页或段映射到物理内存中的不同位置,从而使得程序在运行时可以更高效的利用物理内存。
虚拟内存带来的好处:

  • 可以使得进程得运行内存超过物理内存大小;
  • 进程的虚拟空间相互独立,解决了多进程之间地址冲突的问题;
  • 页表的页表项中除了物理地址外,还有一些标记属性的比特(控制一个页的读写权限,标记该页是否存在),提供了更好的安全性;

Linux是通过对内存分页的方式来管理内存,分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续且尺寸固定的内存空间叫做页(page)。在Linux下,每一页的大小为4kB。虚拟地址与物理地址之间通过页表进行映射。

MMU

MMU 内存管理单元

内存管理单元(MMU)的工作是将虚拟内存地址转化为物理地址;
缺页异常:CPU访问的虚拟内存地址时,MMU没有办法找到对应的物理地址映射关系,会产生一个缺页异常,此时CPU会暂停当前进程,并进入系统内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行。

为什么虚拟内存可以超过物理内存?

  • 地址转换:虚拟地址空间独立于物理内存大小;
  • 分页与交换:仅活跃页面占用物理内存,其余暂存磁盘;
  • 按需加载:程序启动时无需加载全部代码和数据,减少初始内存占用;
  • 共享内存:多个进程可共享同一物理页面(如库文件),减少重复占用。 参考连接:虚拟内存管理

对于一个内存地址转换,总结为以下三个步骤:

  • 把虚拟内存地址,切分成页号和偏移量;
  • 根据页号,从业表里面,查询对应的物理页号;
  • 直接拿物理页号,加上前面的偏移量,就得到了物理内存地址;

段表: 虚拟地址也可以通过段表与物理地址进行映射。
分段机制会把程序的虚拟地址分成 4 个段,每个段在段表中有一个项,在这一项找到段的基地址,再加上偏移量,于是就能找到物理内存中的地址,如下图:

段表

段表

3.2 程序的内存布局

内存布局

程序内存布局