五、编译原理:代码是如何运行的
虽然初级程序员不需要实现编译器,但理解编译过程对调试和性能优化很有帮助。
5.1 编译过程
源代码 → 词法分析 → 语法分析 → 语义分析 → 中间代码 → 优化 → 目标代码
例如: sum = a + b * 10
1. 词法分析:拆分成 Token
[IDENT(sum)] [ASSIGN(=)] [IDENT(a)] [PLUS(+)] [IDENT(b)] [STAR(*)] [NUMBER(10)]
2. 语法分析:生成 AST(抽象语法树)
=
/ \
sum +
/ \
a *
/ \
b 10
3. 语义分析:类型检查、符号表管理
- a 和 b 必须是数字
- 10 是整数
4. 中间代码生成:三地址码
t1 = b * 10
t2 = a + t1
sum = t2
5. 优化
t1 = b * 10
sum = a + t1
6. 目标代码生成(汇编)
LOAD R1, b
MUL R1, 10
LOAD R2, a
ADD R2, R1
STORE sum, R2
5.2 JavaScript 的编译执行
JavaScript 是解释型语言,但现代引擎(V8)使用 JIT(即时编译)技术。
// V8 执行 JavaScript 的过程
//
// 源代码 → 解析器 → AST → 解释器(Ignition) → 字节码 → 执行
// ↓
// 热点代码检测
// ↓
// 编译器(TurboFan) → 优化机器码
// 帮助 JIT 优化的代码写法
// ✅ 保持对象形状一致(有利于隐藏类优化)
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
const points = [];
for (let i = 0; i < 10000; i++) {
// 所有对象都有相同的属性顺序
points.push(new Point(i, i * 2));
}
// ❌ 动态添加/删除属性(破坏隐藏类)
const p = { x: 1 };
p.y = 2; // 改变了对象形状
delete p.x; // 再次改变
// ✅ 使用单态函数(参数类型一致)
function add(a, b) {
return a + b;
}
// 始终传入数字
for (let i = 0; i < 10000; i++) {
add(i, i + 1); // 被优化为数字加法
}
// ❌ 多态调用(参数类型变化)
add(1, 2); // 数字
add("a", "b"); // 字符串 → 导致去优化
六、综合实战:排查线上问题
把计算机基础知识综合运用于实际问题排查:
案例:CPU 100% 问题排查
// 问题代码:死循环导致 CPU 飙升
function processQueue(queue) {
// ❌ 死循环:当 queue 为空时,一直空转
while (true) {
if (queue.length > 0) {
const item = queue.shift();
process(item);
}
// 缺少等待机制
}
}
// ✅ 正确的实现
function processQueueWithBackoff(queue) {
function process() {
if (queue.length > 0) {
const item = queue.shift();
process(item);
setImmediate(process); // 让出 CPU
} else {
setTimeout(process, 100); // 队列为空时休眠
}
}
process();
}
案例:内存泄漏排查
// 使用 Node.js 的 heap snapshot 功能
// 1. 启动时增加 --inspect 参数
// node --inspect app.js
// 2. 在 Chrome DevTools 中分析 heap snapshot
// 常见内存泄漏的修复
class EventManager {
constructor() {
this.listeners = new Map();
}
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event).add(callback);
// ✅ 返回取消订阅函数,方便清理
return () => {
this.listeners.get(event)?.delete(callback);
};
}
}
// 使用 WeakMap 自动清理
const userCache = new WeakMap(); // 当对象被回收时,缓存自动清理
附:知识体系总结
计算机基础
├── 计算机组成原理
│ ├── 二进制与位运算
│ ├── 内存层次结构
│ └── CPU 工作原理
├── 操作系统
│ ├── 进程与线程
│ ├── 并发与并行
│ ├── 死锁
│ └── 内存管理
├── 计算机网络
│ ├── TCP/IP 协议栈
│ ├── HTTP/HTTPS
│ ├── DNS 解析
│ └── 浏览器工作原理
├── 数据库
│ ├── SQL 语言
│ ├── 索引原理
│ ├── 事务与 ACID
│ └── 设计范式
└── 编译原理
├── 编译过程
└── JIT 编译