跳到主内容
@wquguru
精选72Hacker News Best(web_list)技巧与观点

Rust Glancer:基于 Rust LSP 实现极低内存占用

原文
发到 X

I want to present a project that I've been working on for the past 4 months: an alternative Rust LSP implementation that is built with a focus on low memory usage.

我想介绍一个我过去4个月一直在开发的项目:一个专注于低内存使用的替代性 Rust LSP 实现。

It has two main features:

它有两个主要特性:

  • It can use very little memory (target <100mb for reasonable projects). There are caveats, these are described below.
  • It allows immediate indexing after restart: if your project was indexed, restarting the editor will not require re-indexing.
  • 它可以占用极少的内存(针对合理规模的项目,目标 <100MB)。但有一些注意事项,下文会详细说明。
  • 它允许重启后立即索引:如果你的项目已经被索引过,重启编辑器将不需要重新索引。

Your browser does not support embedded videos. You can download the recording instead.

你的浏览器不支持内嵌视频。你可以改为下载录像。

Note: throughout this video, the used RAM remained under 100mb

注意:在整个视频中,使用的 RAM 始终保持在 100MB 以下

These features make Rust Glancer suitable for the older computers: I have tested it on my old MacBook Pro M1 2020 with 8GB RAM, and it was pretty good.

这些特性使得 Rust Glancer 适合老旧电脑:我在 8GB 内存的旧款 MacBook Pro M1 2020 上测试过,效果相当不错。

MachineLSPBase indexing (engine usable)Full indexing
MacBook Pro M4 Max, 36GB (2025)Rust Glancer5 seconds8 seconds
MacBook Pro M4 Max, 36GB (2025)rust-analyzer6 seconds13 seconds
MacBook Pro M1, 8GB (2020)Rust Glancer6 seconds9 seconds
MacBook Pro M1, 8GB (2020)rust-analyzer7 seconds14 seconds
机器LSP基础索引(引擎可用)完整索引
MacBook Pro M4 Max, 36GB (2025)Rust Glancer5秒8秒
MacBook Pro M4 Max, 36GB (2025)rust-analyzer6秒13秒
MacBook Pro M1, 8GB (2020)Rust Glancer6秒9秒
MacBook Pro M1, 8GB (2020)rust-analyzer7秒14秒

As you can imagine, 4 months is not a lot of time for a project as big as a Rust LSP. Rust Glancer is not a complete LSP yet, it has a lot of missing functionality, it has some known bugs, and it has a lot of things I want to improve.

正如你所想,对于一个像 Rust LSP 这样庞大的项目来说,4个月的时间并不算长。Rust Glancer 目前还不是一个完整的 LSP,它还缺少很多功能,存在一些已知 bug,并且有很多我想要改进的地方。

At the same time, it is already pretty capable: it has a full indexing pipeline with type inference and a trait solver (chalk), most of the "normal" Rust syntax is supported, and most of the "normal" LSP actions do work as well: goto definition, hover, inlay hints, completions, you name it.

同时,它已经相当能干:它拥有完整的索引管道,包括类型推断和 trait 求解器(chalk),支持大部分“常规” Rust 语法,以及大多数“常规” LSP 操作也能正常工作:跳转到定义、悬停提示、内联提示、补全等,应有尽有。

If you are interested, you can already try it out: just install the VS Code extension here, or, if you prefer, build and install the vsix from the repository.

如果你感兴趣,现在就可以尝试一下:只需在此处安装 VS Code 扩展,或者,如果你愿意,也可以从仓库构建并安装 vsix 文件。

The rest of the post contains the history of the project: motivation, LLM use, plans and roadmap. If you're not interested, you might want to check out the project documentation instead.

本文的其余部分包含该项目的历史:动机、LLM 的使用、计划和路线图。如果你不感兴趣,可能更想查看项目文档。

Difference with rust-analyzer

与 rust-analyzer 的区别

There are several reasons why rust-analyzer consumes a lot of memory:

rust-analyzer 消耗大量内存有几个原因:

  • Rust workspaces genuinely have a lot of information that must be indexed: thousands of functions, structures, traits, relationships between these, function bodies and statements in them, etc. Each of these needs to be analyzed and remembered, and you can't really cheat if you want to have things like "find all references to this structure".
  • rust-analyzer uses salsa as its database. It's an incremental query-based database, which lazily computes all the data you need without having to explicitly "record" everything. It is a very cool approach, but it's inherently tied to memory, which makes it hard to move parts of data from memory elsewhere.
  • rust-analyzer uses rowan for syntax tree representation. The cool property here is that it allows partial invalidation: if only a part of the file changed, only the relevant bits have to be reparsed, which makes it faster than having to re-parse the whole file on each keystroke. However, the tree-like representation inside of it can cause heavy memory fragmentation (meaning that the amount of RAM taken from the OS is higher than the amount of "actually used" RAM).
  • Rust 工作区确实包含大量必须被索引的信息:数千个函数、结构体、trait、它们之间的关系、函数体及其中的语句等。每一个都需要被分析和记住,如果你想实现诸如“查找此结构体的所有引用”这样的功能,就无法真正走捷径。
  • rust-analyzer 使用 salsa 作为其数据库。它是一个基于增量查询的数据库,能够按需惰性计算所有所需数据,而无需显式地“记录”所有内容。这是一种非常酷的方法,但它本质上与内存紧密绑定,这使得将部分数据从内存移动到其他位置变得困难。
  • rust-analyzer 使用 rowan 来表示语法树。这里的一个巧妙特性是它允许部分失效:如果只有文件的一部分发生了变化,则只需重新解析相关的部分,这比每次按键都重新解析整个文件要快。然而,其内部的树状表示可能导致严重的内存碎片化(意味着从操作系统获取的 RAM 量高于“实际使用”的 RAM 量)。

(1) is something we have to live with (though there are a few optimizations we can do there which Rust Glancer does), but (2) and (3) are the consequences of the rust-analyzer architecture. rust-analyzer chose them to make the LSP faster, and it does work for that purpose.

(1) 是我们必须接受的事实(尽管我们可以做一些优化,Rust Glancer 就是这样做的),但 (2) 和 (3) 是 rust-analyzer 架构的后果。rust-analyzer 选择这些方案是为了让 LSP 更快,并且它在实现这一目标上确实有效。

The idea I had when I started the project: what if we don't try to make an incremental LSP? What if all we have is a frozen analysis result that gets invalidated on save? It obviously will not be as fast as rust-analyzer, but it will give us the properties we seek:

我在启动项目时的想法是:如果我们不尝试构建一个增量式的 LSP 会怎样?如果我们只拥有一个在保存时失效的冻结分析结果呢?它显然不会像 rust-analyzer 那样快,但它将赋予我们所需的特性:

  • analysis results can be offloaded to the filesystem and loaded to memory only when they are actually needed.
  • saved analysis is reusable, and since it's already offloaded to the filesystem, it can be reused after the editor restart.
  • 分析结果可以卸载到文件系统,并在真正需要时才加载到内存中。
  • 已保存的分析结果是可重用的,而且由于它已经卸载到了文件系统,因此在编辑器重启后也可以重用。

This is the core idea of Rust Glancer.

这就是 Rust Glancer 的核心思想。

It indexes the workspace once and preserves results in the filesystem, and then whenever queries need something, they can load the required information for the duration of the query.

它对工作区进行一次索引并将结果保留在文件系统中,然后每当查询需要某些内容时,它们可以在查询期间加载所需的信息。

It doesn't come for free though: frozen workspace analysis is slower than lazy incremental by definition, since loading and deserializing data from filesystem is slower than loading from memory. To mitigate that, Rust Glancer has to use some tricks: for example, when you type, it doesn't perform full blown analysis on each keystroke, it instead attempts shallow analysis of the current body and reuses the previous complete index. This makes completions reasonably fast, but it also means that new items (imports, structures, traits) are not "indexed" until you save the document. Which, hopefully, should not be a problem: you really get used to it fast, and at least in my case it does not feel overly wrong after a while. If that sounds scary, I suggest to just try it, it really is not.

不过,这并非没有代价:冻结工作区分析在定义上比惰性增量分析更慢,因为从文件系统加载和反序列化数据比从内存中加载要慢。为了缓解这一问题,Rust Glancer 必须使用一些技巧:例如,当你输入时,它不会对每次击键执行完整的分析,而是尝试对当前代码块进行浅层分析并复用之前的完整索引。这使得补全速度相当快,但也意味着新项目(导入、结构体、特征)在你保存文档之前不会被“索引”。希望这不会成为问题:你很快就会习惯它,而且至少在我的案例中,过一段时间后并不会觉得过于别扭。如果这听起来很可怕,我建议直接尝试一下,它真的没那么糟。

For people who rely on agentic workflows, Rust Glancer is also optimized for large amount of out-of-editor changes. I'm not sure why, but in rust-analyzer I've observed that when agents edit the code, inlay hints can get out of place, and I had the same problem in Rust Glancer initially, but it was resolved by implementing a custom file watcher and tweaking it somewhat. The server also has lower priority for out-of-editor changes, so agentic changes do not cause rapid re-indexing.

对于依赖智能体工作流的人来说,Rust Glancer 也针对大量编辑器外部的更改进行了优化。我不确定原因,但在 rust-analyzer 中我观察到,当智能体编辑代码时,内联提示可能会错位,起初我在 Rust Glancer 中也遇到了同样的问题,但通过实现自定义的文件监听器并进行一些调整解决了这个问题。服务器对编辑器外部更改的优先级较低,因此智能体的更改不会导致快速的重新索引。

Still, it's important to understand that Rust Glancer has some benefits, but also has some drawbacks (besides being incomplete, obviously) compared to rust-analyzer. Maybe I will manage to solve some of them eventually, but it's highly unlikely that Rust Glancer will ever become "just like rust-analyzer, but better". I imagine that rust-analyzer will remain the default choice for projects that care about completeness and keystroke accuracy, while Rust Glancer will work for people with weaker machines or people who are ready for some sacrifices to reduce RAM usage.

尽管如此,重要的是要理解 Rust Glancer 有一些优势,但与 rust-analyzer 相比也有一些缺点(显然除了不完整之外)。也许我最终能解决其中一些问题,但 Rust Glancer 永远不可能变成“就像 rust-analyzer,但更好”的可能性极低。我认为,对于那些重视完整性和按键准确性的项目,rust-analyzer 仍将是默认选择,而 Rust Glancer 将适用于配置较低的机器用户,或者那些愿意做出一些牺牲以减少 RAM 用量的用户。

How and why it happened

它是如何以及为何发生的

I have been writing Rust professionally for ~7 years, and since pretty early on I started observing how the compiler and its tooling are developed. I've made some contributions to rustc, clippy, and rust-analyzer, and I've spent dozens of hours reading its source code just to teach myself. So I was pretty much aware how big of a project a Rust LSP is.

我已经专业地编写 Rust 大约 7 年了,从很早开始我就开始观察编译器及其工具链的开发过程。我对 rustc、clippy 和 rust-analyzer 做出了一些贡献,并且花了数十个小时阅读其源代码以自学。因此,我非常清楚一个 Rust LSP 项目有多么庞大。

At the same time, I have a love-hate relationship with rust-analyzer. It is absolutely beautiful except for two things: memory usage and initial indexing (especially with build scripts / proc macros enabled). These problems seem to be brought up quite a lot, but in my case they are even more drastic: I have a rather stupid workflow where I have two identical IDEs open on two displays with a bunch of projects inside a workspace. So the memory consumption is roughly 2N, and with my last set of the projects I had to work on, rust analyzer was consuming 16GB of memory that I, ugh, would prefer to have available for other uses; not to mention that each time I opened VS Code, my PC fans would go brr because of a ton of parallel indexing jobs.

与此同时,我对 rust-analyzer 又爱又恨。它非常优秀,除了两点:内存占用和初始索引(尤其是在启用了构建脚本 / proc macros 的情况下)。这些问题似乎经常被提及,但在我这里情况更为严重:我有一个相当笨拙的工作流,我在两个显示器上打开了两个相同的 IDE,里面包含工作区中的多个项目。因此内存消耗大约是 2N,而在处理我上一组项目时,rust-analyzer 占用了 16GB 的内存,呃,我更希望这些内存能用于其他用途;更不用说每次我打开 VS Code 时,由于大量的并行索引任务,我的电脑风扇都会狂转。

At some point I thought that I am fairly confident in my Rust knowledge, so I probably don't need a full-blown LSP, and can use something simpler and more memory efficient. I decided to try building a "smart ctags for Rust". I very explicitly did not want to build an alternative LSP, because of how insane of a task it is. Little did I know...

有一段时间我认为自己对 Rust 的知识已经相当自信,所以可能不需要一个功能完整的 LSP,可以使用更简单、更节省内存的工具。我决定尝试构建一个“针对 Rust 的智能 ctags”。我非常明确地不想构建一个替代性的 LSP,因为那是一项疯狂的任务。但我当时并不知道……

更进一步:量化金融体系

看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力

进入量化体系 →

相似阅读

另一事件,读法相近