计算机系统前置知识

向下滚动可查看阅读进度

前端计算机系统八股前置知识

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

最核心的几句话:

  1. 进程负责资源,线程负责执行。
  2. 同一进程中的线程共享大量资源,不同进程之间通常相互隔离。
  3. 并发不一定是真正同时执行,并行才是真正同时执行。
  4. Stack 是 LIFO,Queue 是 FIFO。
  5. 多线程共享数据可能产生 Race Condition。
  6. Lock 可以解决竞争,但锁使用不当可能产生 Deadlock。
  7. I/O 通常比 CPU 计算慢得多,所以异步和非阻塞很重要。
  8. 浏览器最终也是运行在操作系统上的普通应用程序。