面向数据设计打造高性能解析器
来源:arshad.fyi — 2026-07-13
📋 概述
Arshad Yaseen 分享了构建 Yuku(一个用 Zig 编写的 JS/TS 解析器)过程中的核心设计决策:用扁平 u32 索引数组替代指针树来存储 AST。传统 AST 中每个节点都是独立堆分配,导致缓存未命中、内存碎片和序列化困难;Yuku 将所有节点紧凑排列在单个数组中,遍历从指针追逐变为线性扫描,性能比 npm 上的替代方案快 3-10 倍。文章从硬件事实出发,逐一详解了索引替代指针、紧凑打包、空终止字符串池和零拷贝反序列化的实现细节。
🔑 核心要点
- 缓存未命中的代价约 100ns,而算术运算不到 1ns——追逐散布在堆中的指针让程序几乎停滞在加载等待上
- Yuku 将 50,000+ 个 AST 节点(100KB 文件)存储在单个扁平数组中,从数万次 malloc/free 降为几次分配和一次释放
- 每个节点固定 48 字节(12 个
u32 槽位),编译时验证所有节点类型是否适配,溢出则在构建时直接报错
- 标识符采用空终止字符串池:所有标识符拼接在一起,节点只存储
u32 偏移量,彻底消除指针
- 序列化是 零拷贝 memcpy:因为全是整数偏移,64KB 的 AST 写入 SharedArrayBuffer 只需 0.4ms
- 标识符扫描的热路径使用 256 字节查找表,ASCII 范围直接查表返回布尔值,非 ASCII 走 UTF-8 慢路径
💡 金句
语法从来不是解析器的瓶颈——"一个节点在内存中长什么样"才是。用数组索引替换指针树,你就把随机内存访问变成了连续的缓存友好型扫描。
← 返回 Lobsters 首页