Nick zhu
Senior Program Manager, Developer Division at Microsoft
大家好,欢送来到最新的 Visual Studio Code Java 更新!在这篇文章中,咱们将深刻解析最近代码补全的性能优化。
性能晋升 – 更快的代码补全
随着 Java Language Server 最近 1.0 版本 的公布,咱们对代码补全的性能进行了重大的改良。下图比拟了最近几个版本之间的代码补全响应工夫。对于补全类型、构造函数名等常见的场景,代码补全性能较之前版本(v0.80、v0.81、v.0.82)有显著的晋升。
性能改良总览
代码补全引擎由三个阶段组成:
- 阶段一 (P1) – 搜寻索引器以查找倡议
- 阶段二 (P2) – 转换倡议为补全信息
- 阶段三 (P3) – 计算代码片段倡议
依据咱们的剖析,咱们发现所有三个阶段都有改良的空间。下表显示了咱们在过来版本中所做的改良。咱们将在下一节中更多地探讨这些变动的细节。
要害改变细节
版本 0.81.0 – 缩小 Windows I/ O 操作. #1831
在过来的性能测试中,咱们发现很大一部分工夫老本花在了计算文件 URI 下面。这个发现佐证了咱们之前的察看:因为 JVM 中特定于平台的文件系统相干实现,Windows 平台上的代码补全性能绝对较差。通过删除不必要的 URI 计算,咱们进步了性能,尤其是在 Windows 平台上。
版本 0.81.0 – 对常量 / 默认值进行优化. #1835
当咱们实现一个常量字段(例如 Constants.*)时,实现弹出窗口将在抉择列表中显示倡议的字段名称及其常量值(例如 Bit1 : int = 1)。咱们的剖析发现,当类蕴含大量常量字段成员时,这会让补全十分慢。这是因为咱们从 AST Tree 计算字段值,这在操作大文件时开销很大。
为了优化它,咱们决定推延解析常量值。代码补全会简化倡议标签并仅显示字段名称(例如 Bit1 :int)。当您将鼠标悬停在 Javadoc 的实现项上时,才会在 Javadoc 局部显示它的常量值。
以下是一个领有 1400 多行和 150 多个常量字段的类的字段实现的性能比拟。
版本 0.82.0 – 提早解析通用代码片段 Delay resolving generic snippets. #1838
有两种类型的代码段:
- 通用片段(例如 foreach、fori、ifelse 等)
- 类型定义片段(例如类、接口等)
对于通用代码段,它会在构建实现项的“TextEdit”之前评估具备给定上下文的模板,此类评估可能会很低廉。当初咱们将这类评估推延到解决阶段。当代码补全实现项被建设实现之后,模板模式将作为占位符填充。理论值在解决阶段进行评估,这不会阻止实现我的项目的显示。这也是一项对于“提早解析 TextEdit”能够在多大程度上进步性能的试验,并且在大多数状况下,它应该运行良好。
版本 0.82.0 – 优化匿名构造函数 Optimize for anonymous constructors. #1836
当咱们想实现一个新的 Runnable 时, 冀望的后果是这样的:
Runnable() {}
它由两局部组成
- Runnable 名称
- 空白的 body 片段 body () {\n\t\n}
通过性能剖析,咱们发现 CodeFormatUtil.format 破费了大量工夫。
为了有一个正确的缩进和行分隔符,它们被格式化为以后的首选项。格式化是低廉的,并且为所有我的项目(有时多达数千)反复格式化雷同的内容(空体)。为了改良它,咱们将空体格式化进行了一次性的操作并在所有我的项目中重用它。
版本 1.0.0 – 晋升代码补全搜寻速度
为了优化索引搜寻性能,咱们做了两个要害改变。
- 使索引搜寻工作更高效.#1846, #575562
咱们的性能剖析显示,索引查问工作 97% 的 CPU 工夫用于从磁盘加载索引内容的 I/ O 操作。这是因为咱们应用的索引机制偏向于节俭内存并且在搜索引擎中应用很少的缓存。简直每个查问都必须从磁盘从新加载索引内容。一种间接的优化是升高 I/O 的频率。
Java 索引器由多个哈希表组成,每个哈希表用于记录某种类型的代码局部,例如类型申明、办法申明、援用、办法援用等。典型的查问作业从索引中读取一个或多个哈希表,而后连贯这些将条目索引到指标后果中。
当咱们实现类型 / 构造函数名称(例如 Str 或者 new Str)时,索引查问作业读取两个哈希表,一个是用于查找匹配类型名称的 typeDecl 表,另一个是用于查找类文件门路的 documentName 表申明相应的类型。因为咱们的目标只是实现类型名称并主动导入对应的 package,因而 typeDecl 表足以满足咱们的要求,并且不须要类文件门路。咱们的优化是只读取 typeDecl 索引表,后果证实少读取一张索引表能够节俭大量 I/O 老本。
- 优化索引浏览操作. #574464
这个改变来自于社区开发者对上游 JDT 我的项目的奉献。Java 索引应用 UTF-8 对索引字符进行编码。加载索引时,咱们会将它们解码回来。因为大多数索引字符只是 ASCII 字符,咱们优化了解码办法,使其读取 ASCII 更快。
将来打算
咱们下面列出的改良使主动实现速度更快,但咱们还没有实现。将来,性能依然是咱们的首要任务,咱们将持续优化主动实现性能。以下是咱们在将来几个月内打算的一些我的项目:
提早文本解析 (Lazy Resolve TextEdit)
因为大多数语言客户端不反对实现项的提早解析文本编辑,Java 语言服务器必须计算实现响应中所有实现项的文本编辑。这是最低廉的计算的起因。咱们正在与作者单干摸索对提早解析文本编辑的反对。
更高效的索引架构 More Efficient Indexer
以后索引数据对于构造函数等一些代码实现场景来说是不够的。例如,构造函数实现须要晓得该类是否具备泛型类型参数,并决定是否在构造函数援用中增加菱形 <>。构造函数索引表没有蕴含这样的类型参数信息,咱们必须从 Java 模型中解析它们,此类的解析操作老本很大。咱们正在思考优化索引架构以蕴含更多信息。
反馈与倡议
请踊跃应用咱们的产品!您的反馈和倡议对咱们十分重要,并将帮忙咱们做得更好。有几种办法能够给咱们留下反馈:
- 填写中文问卷
- 在这篇文章下留言
- 在咱们的 GitHub repo 上创立 Issue
资源
以下链接和资源能帮忙您更好地理解 Java on Visual Studio Code 的相干信息
- 理解 更多 Visual Studio Code 上 Java的更多信息
- 逐渐摸索 无关 Visual Studio Code 的 Java 教程
欢送关注微软中国 MSDN 订阅号,获取更多最新公布!