Rust in Everything
基于 pulldown-cmark 0.13.5

字符串与内存

pulldown-cmark 的 README 把「a bare minimum of allocation and copying」列为特点之一。这一部分把这句话拆成两个问题来核对。第一,事件里的字符串从哪来:绝大多数直接借用输入,少数要改写的才放到堆上,短的塞进枚举本身。第二,一次解析一共向分配器要了几次内存、多少字节、都给了谁:树、Allocations 的几张表、第二遍的两个栈。代码集中在 strings.rs(432 行,含测试)、parse.rs 里的 Allocations(约 150 行)和 utils.rs(181 行);数字都来自实测,语料是例子文档和本站内容仓库的 1099 篇 Markdown。

  1. CowStr:Borrowed、Inlined、Boxed 三个变体,实测 24 字节,内联最多 22 字节;clone 和 into_static 会换形态;逐条核实解析时哪些情况真的分配,本站语料约 52 万个字符串里只有 36 个 Boxed。
  2. 一次解析分配了什么:计数分配器加栈回溯,逐次列出例子文档的 9 次分配;本站语料每篇中位 8 次,字节主要花在 48 字节一项的树和 10 KB 的固定预留上;TextMergeStream 分配不多,却让迭代慢 27%。
flowchart TB
  input["输入 str"] -->|借用| cow["CowStr"]
  cow --> ev["Event"]
  newp["Parser::new_ext"] --> tree["树 Vec of Node"]
  newp --> al["Allocations 表"]
  al -->|"take 取走"| ev
  tree -->|"第二遍改写"| ev

字符串之外,事件本身多大(Event 80 字节、TagEnd 2 字节)在事件模型;树节点为什么是 48 字节在扁平数组上的树。

💬 关联讨论

发起讨论
加载中...