前端计算机系统八股前置知识
1. CPU 是什么
**CPU(Central Processing Unit,中央处理器)**负责执行程序指令。
例如 JavaScript:
let a = 1;
let b = 2;
let c = a + b;
最终都会被转换成 CPU 能执行的机器指令。
可以简单理解:
CPU = 真正干计算工作的硬件。
CPU 在一个时刻只能执行有限数量的任务,因此操作系统需要负责安排不同程序使用 CPU。
2. 内存 Memory
程序运行时的数据通常需要放在内存中。
例如:
let age = 18;
const user = {
name: "Navi"
};
这些数据在程序运行过程中都需要占用内存。
内存和磁盘的区别
- Memory / RAM:速度快,程序运行时使用,断电后数据通常消失
- Disk / Storage:速度较慢,用于长期保存文件
简单理解:
磁盘
↓
程序启动
↓
加载到内存
↓
CPU 执行
3. 进程 Process
**进程(Process)**可以理解为:
一个正在运行的程序实例。
例如同时运行:
Chrome
VS Code
微信
操作系统会分别管理这些程序对应的进程。
核心特点
不同进程通常拥有彼此隔离的内存空间。
Process A
└─ Memory A
Process B
└─ Memory B
Process A 不能随便读取 Process B 的内存。
因此可以简单记:
进程是操作系统分配资源的基本单位。
4. 线程 Thread
一个进程内部可以有多个线程。
Process
│
├─ Thread 1
├─ Thread 2
└─ Thread 3
线程是真正执行代码的执行流。
可以简单记:
线程是 CPU 调度和执行任务的基本单位。
同一个进程里的线程通常共享:
- 内存
- 文件资源
- 其他进程资源
所以:
不同进程
→ 内存相对隔离
同一进程中的线程
→ 共享大量资源
5. 进程和线程的关系
最简单的类比:
进程 = 公司
线程 = 公司里的员工
公司拥有:
- 办公室
- 设备
- 资金
相当于进程拥有各种资源。
员工真正完成工作,相当于线程执行任务。
因此:
进程负责资源,线程负责执行。
6. 并发与并行
Concurrency 并发
多个任务在一段时间内交替执行。
例如一个 CPU 核心:
任务 A
↓
任务 B
↓
任务 A
↓
任务 C
因为切换很快,看起来像同时进行。
这叫:
Concurrency(并发)
Parallelism 并行
多个任务真正同时执行。
例如多核 CPU:
CPU Core 1 → Task A
CPU Core 2 → Task B
这叫:
Parallelism(并行)
简单记:
并发 = 看起来同时
并行 = 真正同时
7. CPU 调度
电脑通常同时运行很多程序,但 CPU 数量有限。
因此操作系统需要决定:
下一段时间让哪个线程使用 CPU?
这个过程叫:
Scheduling(调度)
例如:
Chrome
↓
VS Code
↓
微信
↓
Chrome
操作系统高速切换不同任务。
因此即使 CPU 核心数量不多,也可以同时运行大量程序。
8. Context Switch 上下文切换
CPU 从线程 A 切换到线程 B 时,需要保存 A 当前的状态,然后加载 B 的状态。
这叫:
Context Switch(上下文切换)
例如:
Thread A 正在运行
↓
保存 A 的状态
↓
切换
↓
恢复 Thread B 的状态
↓
Thread B 运行
上下文切换本身需要消耗一定资源。
所以:
线程并不是越多越好。
9. Stack 栈
**Stack(栈)**采用:
LIFO:Last In, First Out
后进先出
例如:
依次放入:
A
B
C
取出:
C → B → A
常见操作:
push:入栈pop:出栈
程序中的函数调用通常会使用:
Call Stack(调用栈)
例如:
function a() {
b();
}
function b() {
console.log("hello");
}
a();
可以简单理解:
a()
↓
b()
↓
console.log()
执行完以后反向出栈。
10. Heap 堆
**Heap(堆)**是一块用于动态分配数据的内存区域。
例如对象:
const user = {
name: "Navi"
};
可以简化理解:
Stack
user → 引用
↓
Heap
{ name: "Navi" }
因此 Stack 和 Heap 的简单区别是:
Stack
→ 函数调用、局部变量等
→ 管理比较规则
Heap
→ 对象等动态数据
→ 空间更灵活
前端八股阶段知道这个程度就够了。
11. Garbage Collection 垃圾回收
程序使用内存后,如果某块内存已经不再需要,就应该释放。
JavaScript 会自动进行:
Garbage Collection(垃圾回收,GC)
例如:
let user = {
name: "Navi"
};
user = null;
如果原对象已经没有任何引用,垃圾回收器就可以回收它。
12. Memory Leak 内存泄漏
如果已经没用的数据仍然一直被引用,就无法被垃圾回收。
这叫:
Memory Leak(内存泄漏)
例如:
const arr = [];
setInterval(() => {
arr.push(new Array(100000));
}, 1000);
数组不断增长,而且始终存在引用。
结果:
内存占用越来越高
↓
性能下降
↓
甚至程序崩溃
13. I/O 是什么
I/O = Input / Output,输入 / 输出。
例如:
- 读取文件
- 写文件
- 网络请求
- 键盘输入
- 磁盘访问
这些都属于 I/O 操作。
例如:
CPU
↓
请求读取文件
↓
磁盘读取
↓
返回数据
磁盘和网络通常远慢于 CPU。
因此:
CPU 不应该傻等 I/O 完成。
这也是异步编程非常重要的原因之一。
14. 阻塞 Blocking
如果一个线程执行某个任务时,必须一直等待任务完成才能继续:
这叫 Blocking(阻塞)。
例如:
线程
↓
读取文件
↓
等待……
↓
文件读取完成
↓
继续执行
等待期间线程无法执行其他任务。
15. Non-blocking 非阻塞
非阻塞意味着:
发起操作以后,不需要一直原地等待。
例如:
线程
↓
发起网络请求
↓
继续做其他任务
网络请求完成
↓
再通知线程
浏览器中的异步机制大量依赖这种思想。
16. Race Condition 竞态条件
如果多个线程同时修改同一个数据,执行结果可能取决于谁先执行。
例如:
count = 0
Thread A:
读取 count = 0
count + 1
Thread B:
读取 count = 0
count + 1
理论上执行两次:
count 应该 = 2
但因为两个线程都读取到了 0,最后可能得到:
count = 1
这种问题叫:
Race Condition(竞态条件)
17. Lock 锁
为了防止多个线程同时修改共享资源,可以使用:
Lock / Mutex(锁 / 互斥锁)
例如:
Thread A
↓
获得锁
↓
修改数据
↓
释放锁
这期间:
Thread B
↓
想获得锁
↓
必须等待
这样就可以保证某段关键代码同一时间只有一个线程执行。
18. Critical Section 临界区
多个线程访问共享数据时,容易产生竞态条件的代码区域叫:
Critical Section(临界区)
例如:
读取余额
↓
修改余额
↓
保存余额
如果多个线程同时操作,就可能出问题。
所以通常需要:
Lock
↓
Critical Section
↓
Unlock
19. Deadlock 死锁
假设有两个线程:
Thread A:
已经拿到 Lock 1
等待 Lock 2
Thread B:
已经拿到 Lock 2
等待 Lock 1
于是:
A 等 B
↑ ↓
└───┘
双方永远等下去。
这叫:
Deadlock(死锁)
简单理解:
大家都拿着对方需要的资源,又都不肯释放。
20. IPC 进程间通信
因为不同进程的内存通常是隔离的:
Process A
Process B
它们不能直接随便读取对方内存。
所以如果两个进程需要交换数据,需要使用:
IPC:Inter-Process Communication
进程间通信
前端只需要知道:
浏览器不同进程之间也需要通过 IPC 交换信息。
不需要深入背各种 IPC 实现。
21. User Space 与 Kernel
操作系统可以粗略分成:
User Space
用户空间
Kernel
内核
普通程序运行在用户空间,例如:
Chrome
VS Code
Node.js
底层重要功能由操作系统内核提供,例如:
- CPU 调度
- 内存管理
- 文件系统
- 网络
- 硬件访问
所以:
JavaScript
↓
Browser
↓
Operating System
↓
Hardware
22. System Call 系统调用
普通程序不能随便直接操作硬件。
例如浏览器想:
读取文件
发送网络数据
申请内存
通常需要请求操作系统内核完成。
这种请求机制叫:
System Call(系统调用)
不需要记具体系统调用名称,只需要理解:
应用程序很多底层能力最终由操作系统提供。
23. GPU
**GPU(Graphics Processing Unit)**主要擅长:
大量并行计算。
尤其适合:
- 图形
- 像素处理
- 图像
- 页面合成
简单理解:
CPU
→ 通用计算、复杂逻辑
GPU
→ 大规模并行图形计算
因此浏览器绘制页面时会大量利用 GPU。
24. Sandbox 沙箱
**Sandbox(沙箱)**是一种安全隔离机制。
它的核心思想:
限制程序能够访问的资源。
例如网页里的 JavaScript 不能随便:
读取你的所有文件
删除磁盘数据
读取其他程序内存
否则访问一个恶意网站就可能直接控制你的电脑。
所以浏览器会给网页代码设置严格的权限边界。
25. 常见英文术语
| English | 中文 |
|---|---|
| CPU | 中央处理器 |
| Memory / RAM | 内存 |
| Disk / Storage | 磁盘 / 存储 |
| Process | 进程 |
| Thread | 线程 |
| Main Thread | 主线程 |
| Concurrency | 并发 |
| Parallelism | 并行 |
| Scheduling | 调度 |
| Context Switch | 上下文切换 |
| Stack | 栈 |
| Heap | 堆 |
| Call Stack | 调用栈 |
| LIFO | 后进先出 |
| FIFO | 先进先出 |
| Garbage Collection | 垃圾回收 |
| Memory Leak | 内存泄漏 |
| I/O | 输入 / 输出 |
| Blocking | 阻塞 |
| Non-blocking | 非阻塞 |
| Race Condition | 竞态条件 |
| Lock | 锁 |
| Mutex | 互斥锁 |
| Critical Section | 临界区 |
| Deadlock | 死锁 |
| IPC | 进程间通信 |
| Kernel | 内核 |
| User Space | 用户空间 |
| System Call | 系统调用 |
| GPU | 图形处理器 |
| Sandbox | 沙箱 |
26. 最后只需要真正理解这些
CPU
→ 执行代码
Memory
→ 保存程序运行时数据
Process
→ 管理资源
Thread
→ 执行任务
多个 Thread
→ 可能产生并发问题
共享数据
→ Race Condition
解决竞争
→ Lock
锁使用不当
→ Deadlock
进程之间隔离
→ IPC 通信
程序需要文件/网络等能力
→ 通过操作系统
网页权限受限制
→ Sandbox
最核心的几句话:
- 进程负责资源,线程负责执行。
- 同一进程中的线程共享大量资源,不同进程之间通常相互隔离。
- 并发不一定是真正同时执行,并行才是真正同时执行。
- Stack 是 LIFO,Queue 是 FIFO。
- 多线程共享数据可能产生 Race Condition。
- Lock 可以解决竞争,但锁使用不当可能产生 Deadlock。
- I/O 通常比 CPU 计算慢得多,所以异步和非阻塞很重要。
- 浏览器最终也是运行在操作系统上的普通应用程序。