本期检索说明
先读取 content/collections/deep-radar 截至 2026-10-09 的全部原文链接,并按 URL、标题与实现机制去重。最近 24 小时找到 Kotlin/Native 的 batched incremental clean build:它同时给出性能数字、19 个文件的实现 diff 和针对缓存等价性的黑盒测试。回溯至最近 7 天后,再纳入 10 月 10 日凌晨合入 rustc 的 MIR statement-vector 容量收缩。Java/JVM 近期已经连续覆盖较多;Zig 与 Linux 本周期没有同时满足实测数据、源码证据和原理剖析三条红线的新材料,本期不凑数。
证据边界需要先说清:Kotlin PR 截稿时仍在开放评审,作者只披露 batched clean build 的剩余 overhead 约为 10%,没有给出原始秒数、项目规模、重复次数、方差与严格基线定义;本文因此只把它视为方向明确的工程测量,不换算成“快了 90%”。rustc PR 已合入,给出同一 workload 的 RSS 与 instruction-count 权衡,但也只有一个 aws-sdk-ec2 check 样本。两篇都值得读,均不支持外推为所有工程的普遍收益。
| 主题 | 原始发布日期 | 一手来源与交叉验证 | 截稿状态 | 推荐强度 |
|---|---|---|---|---|
| Kotlin/Native 批量构建增量缓存 | 2026-10-10 02:13(中原标准时间) | JetBrains PR #8881 / 19 文件源码 diff / 298 行 CacheBatchTest |
开放评审 | 推荐,重点看 IR Linker 复用与依赖 DAG 约束 |
rustc MIR statement Vec 收缩 |
2026-10-07 10:59(中原标准时间),10 月 10 日合入 | Rust PR #163915 / 单文件 6 行实现 / aws-sdk-ec2 RSS 与指令数 | 已合入 | 强烈推荐,重点看内存节省与指令代价的显式交换 |
01 · Kotlin/Native:把 N 次 cache compilation 合成一次,IR Linker 与依赖反序列化只付一次
原文与日期: Igor Yanovsky(homuroll),2026-10-10 02:13(中原标准时间);JetBrains Kotlin PR #8881、完整源码 diff 与 KT-89840。
为什么值得读: Kotlin/Native 的 incremental compilation 通常讨论“改一个文件以后多快”,但 clean build 同样决定 CI、首次拉仓库和缓存失效后的体验。旧流程按子项目分别启动 cache compilation;每次都创建自己的 KonanIrLinker,并把 stdlib 等共同外部依赖从磁盘重新反序列化。子项目即便并行,重复 I/O、解析和 linker 初始化仍按项目数放大。这个 patch 的价值是把优化边界从“单个子项目内部”上移到依赖图层面:一次编译同时为多份 KLIB 生成 per-file cache。
核心技术结论: CacheBuilder.tryBuildCacheBatch 先选出没有缓存或需要 full rebuild 的 per-file-cache 候选;只有候选至少两项、且每个候选的全部依赖已经有有效缓存或也在 batch 内时,才进入批处理。配置从单值 konanLibraryToAddToCache 扩展为 CACHE_BATCH: Map<canonicalPath, FingerprintHash>,KonanIrLinker 也从单个 libraryBeingCached 改为 librariesBeingCached map。由此一次 compilationSpawner.spawn 可以传入所有 batch libraries,而公共依赖只进入一次 linker/deserializer。
核心筛选逻辑很值得迁移:
val batch = candidates.filter { candidate ->
klibDag.getAllDependencies(candidate).all { dependency ->
dependency in candidatesSet || dependency in rebuiltLibraries ||
(dependency in cacheRootDirectories &&
dependency !in dirtyLibraries && dependency !in needFullRebuild)
}
}
if (batch.size < 2) return null这不是无条件“把任务装进一个大进程”。若某依赖还有待处理的 per-file rebuild,它必须先于 dependent 重建;相关 dependent 会退出 batch,回落到原来的逐库逆拓扑路径。test runner 需要每个 included library 单独编译,也被显式排除。性能优化没有改变缓存依赖顺序和失败回滚语义。
最有价值的实验、源码与 benchmark 细节: 作者报告,原流程对共享依赖反复反序列化;改为一次 IR Linker 后,clean build 的 incremental-compilation overhead 被压到“约 10%”。PR 涉及 19 个文件、+594/-137,并新增 298 行 CacheBatchTest。测试在 Linux/macOS、backendThreads=1 与 4 两种配置下覆盖:首次三库 clean build 生成 5 个 cache archive;无改动再链接不重建;修改上游库后只重建必要缓存;删除两个下游 cache 时得到恰好 2 个 batched archive;当上游存在 pending rebuild 时确认不 batching;最后逐文件比较 batched 与 separate build 的缓存文件列表及字节内容完全一致。
性能数字的限制不应略过:PR 没有公开“10%”的原始时间、机器、样本项目、基线定义和误差区间,因此不能把它解释成 90% 加速,也无法独立计算收益。当前可确认的是:源码确实删除了 N 次 spawn/linker/deserialization 的结构性重复,功能测试又证明串行、并行、增量重建和缓存字节等价;绝对收益仍应在真实 KMP 工程中用 clean build 多轮复测。
适合的工程师背景: 熟悉 Kotlin/Native、KMP Gradle 构建、KLIB/per-file cache、IR serialization,或正在设计跨模块编译缓存与批处理调度的编译器工程师。
预计阅读收益: 约 40–55 分钟;能掌握何时 batching 真正减少公共前置工作、如何用依赖 DAG 保住重建顺序,以及怎样以字节等价测试阻止性能补丁悄悄改变缓存内容。
02 · rustc:缓存 MIR 前对每个 basic block 执行 shrink_to_fit,用 0.3% 指令换 80 MiB RSS
原文与日期: Josh Triplett,2026-10-07 10:59(中原标准时间),2026-10-10 00:24 合入;Rust PR #163915 与 完整源码 diff。
为什么值得读: 编译器内存优化常聚焦某个巨大 arena 或 interner;这个 patch 反而抓住成千上万个小 Vec 的空余 capacity。每个 MIR basic block 都有 statement vector,构建和变换时按 Vec 的扩容策略增长,删除语句后却不会自动缩回实际长度。单个浪费很小,但 MIR 被缓存后存活时间长,乘上所有 basic block 就能形成可见的峰值 RSS。它是“对象数量 × 每对象尾部浪费 × 生命周期”的典型案例。
核心技术结论: 改动只在 rustc_mir_transform/src/lib.rs 增加 6 行,在 mir_promoted 完成 MIR 变换、进入后续缓存生命周期前遍历所有 basic block:
for bb in body.basic_blocks.as_mut_preserves_cfg() {
bb.statements.shrink_to_fit();
}as_mut_preserves_cfg() 明确表示只改 statement storage、不改控制流图。选择缓存前这个时点也很关键:过早收缩可能被后续 pass 再次扩容,制造重复 allocation/copy;太晚则多余 capacity 已经随缓存驻留。shrink_to_fit 可能重新分配并复制,因此这不是免费的内存节省,而是把一次可测的 CPU 成本换成更低的长期驻留。
最有价值的实验、源码与 benchmark 细节: 在 aws-sdk-ec2 check 上,作者报告峰值 max-RSS 减少约 80 MiB,约 1.45%;反推基线峰值约为 80 / 0.0145 ≈ 5.39 GiB。代价是 instruction count 增加 0.3%。代码只改一个文件、增加 6 行,没有借助新的数据结构或复杂启发式;收益因此能直接归因于 statement Vec 的闲置 capacity 被释放。
这组数字比单独写“省 80 MiB”更有工程价值:对内存受限 CI runner 或并发编译节点,1.45% 峰值下降可能提高可并发 job 数;对 CPU 紧张且内存充足的构建机,0.3% 指令回退可能不值得。它也只有一个 workload,不能推断所有 crate 都有相同比例;MIR statement 删除密度、basic-block 数和 allocator 行为都会改变结果。正确的迁移方式是同时跟踪 max-RSS、instructions 与 wall time,而不是把 shrink_to_fit 当通用“最佳实践”。
适合的工程师背景: 熟悉 rustc MIR、编译器缓存生命周期、Rust Vec capacity/allocator 行为,或正在排查大量小容器造成峰值内存膨胀的系统工程师。
预计阅读收益: 约 20–30 分钟;能学到如何从“每对象几乎看不见”的 capacity 浪费追到进程级 RSS,以及如何选择收缩时点并量化 CPU/内存交换。
中国大陆 ToC 硬件价格观察
数据口径
窗口为 2026-09-11 至 2026-10-10,单位人民币,六类硬件固定同一 SKU。今天通过公开比价页的实时渲染结果复核到 CPU、GPU、主板、HDD、SSD 五类报价;DRAM 页面仍明确显示“暂无报价”,因此不新增点。重复价格作为真实采样保留,用来区分“已复核横盘”和“未取得数据”。SSD 只采用当前 2TB 规格的全网比价栏,不采用跨容量聚合的“¥819 起”。
| 类别 | 10 月 10 日可复核价 | 30 日窗口内真实走势 | 建议 |
|---|---|---|---|
| CPU | Ryzen 7 9800X3D,京东 ¥2,609 | 9/14 ¥2,639 → 9/23 ¥2,579 → 10/1–8 ¥2,694–2,699 → 10/9–10 ¥2,609 | 可关注但不追价;连续两日维持 ¥2,609,仍高于窗口低点 ¥30 |
| GPU | MSI RTX 5070 VENTUS 3X 12G,亚马逊中国 ¥4,464.34 | 9/11–10/10 多次实时复核均为 ¥4,464.34 | 刚需可比价后入手;单一渠道横盘不等于全市场没有促销 |
| 主板 | ASUS TUF B850M-PLUS WIFI7,天猫 ¥1,299 | 9/11–10/10 多次复核均为 ¥1,299 | 刚需可入;公开最低价稳定,但下单前核对店铺与售后 |
| DRAM | 暂无报价;最后可复核 9/9 ¥3,900 | 本窗口没有可比报价 | 观望;固定 SKU 缺价,不用其他容量、颗粒或时序替代 |
| HDD | IronWolf Pro 8TB ST8000NE001,i百联 ¥1,849 | 9/11–10/10 多次复核均为 ¥1,849 | 容量刚需可买;先核对型号、五年保修与数据恢复服务 |
| SSD | ZHITAI Ti600 2TB,京东 ¥1,799 | 9/23–10/10 多次复核均为 ¥1,799 | 观望或确认结算价后入手;2TB 比价横盘,聚合栏可能滞后 |
价格来源: 9800X3D、MSI RTX 5070 VENTUS 3X、ASUS TUF B850M-PLUS WIFI7、Kingston FURY DDR5-6000 32GB、IronWolf Pro 8TB、ZHITAI Ti600 2TB。
判断依据
五个有报价的固定 SKU 今天全部与昨日一致。CPU 在 10 月 9 日从 ¥2,699 回落至 ¥2,609,今天维持该价,但仍比 9 月 23 日低点 ¥2,579 高 ¥30;两天数据还不足以确认继续下跌。GPU、主板、HDD 与 SSD 只是同一公开渠道再次复核到相同最低价,不能外推为整个中国零售市场稳定。DRAM 固定 SKU 继续缺价,走势图保留真实空白尾段。SSD 页面头部“¥819 起”是跨容量聚合口径,当前选中的 2TB 规格全网比价仍为 ¥1,799,二者不能混用。本期购买建议只依据可复核价格序列,不引用未核实的新品或产能传闻。
本期结论
两篇材料都在处理“为以后保留的余量”何时变成浪费。Kotlin/Native 把按子项目隔离的 cache compilation 合成批次,用依赖 DAG 与缓存指纹守住正确性,从结构上消除公共依赖的重复反序列化;rustc 则在 MIR 即将长期缓存前释放 statement vector 的空闲 capacity,以 0.3% 指令换取 aws-sdk-ec2 约 80 MiB、1.45% 的峰值 RSS。可迁移的方法不是一律 batching 或一律 shrink_to_fit,而是先定位重复初始化与长生命周期闲置容量,再用等价性测试和 CPU/内存双指标验证交换是否值得。