一个GitHub项目最近把标题写成了脏话——“shitty”,副标题却一本正经:“a serious terminal emulator with a stupid name”。开发者pg83用C++23重写了老牌终端模拟器Zutty,打出的口号是“Blazingly fast. Memory-unsafe and faster than yours”。翻译过来就是:跑得比你快,代价是我不管内存安全。

在一台Apple Silicon MacBook上,统一字体、统一格子尺寸、统一80x24网格之后,shitty cat 100MB可打印ASCII数据只用了0.81秒,约118 MiB/s,比Alacritty 0.17.0的99 MiB/s、Kitty 0.48.2的75 MiB/s、Ghostty 1.3.1的64 MiB/s都快。换成夹杂无效UTF-8的随机字节这种最差场景,shitty仍有约51 MiB/s,Alacritty掉到31 MiB/s,Ghostty只剩21 MiB/s,Kitty则干脆没跑出数据——它遇到乱码里的转义序列,忙着改标题、响铃,没工夫渲染。

故意找茬的技术选型

这场跑分背后其实是一场路线之争。这几年主流终端模拟器几乎都在往“安全语言+GPU渲染”上靠:Alacritty用Rust,Ghostty由Mitchell Hashimoto主导、用Zig写,Kitty用Python做配置层、C做渲染内核。共同逻辑是:内存安全语言换来更少的崩溃和漏洞,代价是运行时开销。

shitty反过来赌了一把:手写内存管理,不用安全语言兜底,换取更小的开销和更高吞吐。这不是新故事,系统编程圈子里“安全语言的性能税”和“裸机手写优化”的争论打了很多年,只是这次战场换成了终端模拟器,而且发帖人自己先把“内存不安全”这个通常被回避的词写进了标题。

ASCII场景吞吐对比 (MiB/s) shitty 118 alacritty 99 kitty 75 ghostty 64 100MB可打印ASCII,同字体/同cell/同网格条件下的墙钟吞吐

这组数字测的到底是什么

问题在于,跑分测的是“终端接受字节有多快”,不完全等于“终端画出来有多好”。这是两件不同的事:如果生产者进程被阻塞,或者终端在高速输入下丢帧、合并帧,PTY吞吐数字可以很漂亮,视觉保真度却可能悄悄打折。原文的100MB cat测试只报告了前者,没有单独给出帧率、丢帧率这类渲染侧指标,这一层区分在原文里是缺失的。

同样值得重新读一遍的是Kitty“交白卷”这件事。原文把它写成短板——遇到随机字节里的转义序列,Kitty只顾着改标题、响铃,没渲染出内容,自然测不出吞吐。但这也可以反过来看:面对来路不明、可能带攻击意图的字节流,选择保守响应而不是硬解析,是一种稳健性取舍,不必然是性能失败。

一个数字,两种解释 PTY吞吐 字节被终端接受的速度 原文唯一给出的指标 可能掩盖丢帧/延迟 渲染帧行为 帧率、丢帧、显示延迟 原文未单独报告 决定真实观感

“不安全”三个字,放对场景才重

终端模拟器有一个天然特殊性:它每天都在解析来自不可信来源的字节流——SSH到陌生主机、cat一个不认识的日志文件、下载后随手打开的文本。这些字节里可能夹带精心构造的转义序列,历史上终端软件因为解析这类输入出过安全问题,不是新鲜事。

shitty选择用C++手写内存管理去处理这条输入路径,等于把“内存不安全”直接摆在了攻击面最集中的地方。项目页面提到用了sanitizer做CI检查,这能筛掉一部分内存错误,但和Rust、Zig从语言层面强制的边界检查不是一回事。对日常要SSH到各种主机、要处理陌生文件的开发者和系统管理员来说,选一个终端模拟器,安全边界是否清楚,比跑分表上的MiB/s更该问一句。

  • 风险.内存不安全的解析器面对不可信转义序列,是终端模拟器历史上反复出问题的攻击面。

社区还没给出答案

一个自嘲意味浓厚的项目名,加上正面挑衅安全语言阵营的口号,很容易被读成一次话题性发帖,而不是严肃的生产级承诺。但目前没有可靠渠道能核实Hacker News等社区对“内存不安全但更快”这个定位的真实反应——不确定它引发了广泛认可还是被当成一次玩笑,不宜替读者下结论。

快是真快,但输赢在解析器里,不在跑分表里。

接下来值得盯的,是有没有第三方独立复现这组基准、有没有安全研究者去审计它解析转义序列的那段代码,以及Alacritty、Kitty、Ghostty的团队会不会正面回应这次对比。在那之前,这更像一次精心设计的单场景挑衅,还不是一个能被验证的工程结论。