ReSharper 高效攻略
每次ReSharper更新后,我们都会收到关于其性能的一些问题。
有的用户注意到到加载解决方案略有些慢,有的发觉索引有些滞后,还有的看到一条黄色通知栏,上面说明 “JetBrains ReSharper Ultimate’ likely caused 9 seconds of unresponsiveness. Disabling it may improve your experience.” – 是的, 我们还见到过更高的值。
我们听到了您的意见,我们用ReSharper来开发ReSharper。也许并不总是那么明显,但我们正不断努力改善ReSharper的性能。
因为这些改进并不总是为人所知,于是我们决定开始发布一系列博客,讲述关于正在发生的这些大小改进。
我们将接触到一些高层次的东西,还会揭示一些幕后的东西。
在本系列中:
-
ReSharper 高效攻略
-
将ReSharper从进程中取出
-
组件合成、即时编译、UI线程
-
ReSharper 2018.1和2018.1.1的性能改进
请注意,这些博文会很长 – 会涉及很多上下文。所以,让我们从头开始,先回顾一点历史!
Visual Studio 和 ReSharper
Visual Studio为很多开发人员提供了跨Windows、Web、多个云和移动平台的服务。
它建立在多年工作的基础上,并且经过了多次变化。
加入新语言和框架,经常还有新的开发范例。
C#编译器变为Roslyn,在Visual Studio中加入更多代码分析和重构功能。
开发工作总是日新月异,由于Visual Studio架构的扩展性非常强,所以一直能够紧跟新的开发趋势,并提供丰富的IDE体验。
插入到这种可扩展的架构中,ReSharper提升了Visual Studio的价值,扩展了现有功能,并且提供其他功能,比如更多代码分析规则和快速修复、结构化搜索和替换、55个重构、改善代码生成、生成和调试功能等等 – 在我们的ReSharper vs. Visual Stuido概述中查看。
另一方面,ReSharper也考虑到不仅仅只对最新版Visual Studio要进行扩展。
出于很多原因,我们的很多客户还在使用以前版本的Visual Studio,用ReSharper还可以扩展Visual Studio 2010 SP1、2012(所有三次更新)、2013(所有五次更新)、2015(所有三次更新),以及2017不断的更新。
这意味着ReSharper仍然了解project.json
,具备加载轻量级解决方案的知识(引入了这些知识但后来又删掉了),等等。
我们在此想阐明的是:两种产品本质上都很复杂。
而且甚至更复杂!
您是否曾想过,IDE处理未经编译的残缺损坏的代码有多困难?
我们写代码时总是发生这种情况……而损坏的代码是可以重构的!
我们可以在项目中导航!
还有代码补全!
Visual Studio和ReSharper能做到这点真的很棒!
就我个人而言,绝不愿意转回使用1998年的基本工具 – 丰富的IDE是在太棒了!
The 32-bit cage match
自Visual Studio问世以来,有一点一直没变:一直是32位进程。这意味着在最好情况下(在64位操作系统上作为32位程序运行),它只能使用约3 GB内存。实际上,只能使用约2.5 GB内存。
并非所有空间都能有效使用,因为还有“保留内存”:为将来使用而预先分配的内存,用于在进程间通讯、从磁盘映射文件,块没有足够可用空间供.NET运行时存储其对象……
在剩余可用内存空间中,它还必须承载自己的功能,Roslyn引擎,和安装ReSharper之后的ReSharper引擎。还有整个IDE中可用的所有操作和命令。
如果我们在任何时候将Visual Studio配置为启用ReSharper,可以看到在垃圾回收(Garbage Collection, GC)上花了大量时间 – 本快照中是不错的12%。(这是发生在加载解决方案期间)
(注意:正如我们在快照中所见,Visual Studio启动时花了大量时间在即时(Just-in-Time, JIT)编译上 – 我们将在本系列以后的文章中介绍。)
在32位进程中,GC的运行频率可能超过最佳值,例如内存不足时。
在64位进程中,可能需要清扫更多对象,但因为没有达到上限,进行这一过程的次数将会少很多,并且在更优化的时间进行。
“如果微软会将Visual Studio编译为64位可执行程序就好了!将确保有更多可用内存,而且一切都没有问题!是吗?”很多人一直在要求:请让Visual Studio成为64位可执行程序。
该话题中的第一条评论提到这一点并不容易。
程序集可能变得更大,IDE实际上可能会变得更慢,因为会有更多内存需要管理(可能需要更多时间和资源来执行垃圾回收)。怎么可能?Visual Studio和ReSharper在很多地方都要使用内存,但先让我们将重点放在许多例子中的一个上。Visual Studio和ReSharper都在内存中保留语法树。我们项目中的所有代码都被解析为一个语义模型和一棵语法树。
Roslyn使用不变的树,这在处理语法时很棒,但也意味着在扰动下的代码会创建许多生命周期不短且必须被垃圾回收的对象。
ReSharper与其PSI方法不同 ,而且如何在内存中建模和处理语法和语义也不同。某些语法和语义结构将一次生成且不会改变。
所以,在生命周期短的对象之后,Roslyn以及ReSharper最终都有很多生命周期长的对象。
在.NET运行时中这些问题如何呢?
第2代。第2代垃圾回收通常耗时更长,因为对象在引用它们的地方有更多根。
这样是不是不好?完全不会。Roslyn和ReSharper都重新使用代码的已知信息,将包含该信息的对象保存在内存中。
如果一直需要重新创建这些对象,我们的IDE将会变慢,所以将它们保存在内存中是一个很好的方法。只是运行垃圾回收器可能需要更长时间。
改为64位进程只会使垃圾回收(GC)时扫描更多对象,可能导致GC暂停,花费更多时间。
关于64位Visual Studio有更多考虑因素,例如必须确保Visual Studio的整个生态系统扩展也移植到64位。
关于这方面的另一篇有趣的文章是Visual Studio: Why is there no 64 bit version?(目前为止)。
简而言之,似乎不会很快推出64位版(如果有的话)。
这意味着微软、JetBrains和其他扩展功能开发商必须依靠巧妙的技术来改善性能。
阴谋论!
在本介绍性文章中,让我们再讨论一个罕见的问题……有很多人问我们,JetBrains是否打算减缓ReSharper的工作而推动Rider。
绝对不是这样的!
Rider不能独立于ReSharper而存在(它们共享代码库),我们在其中任何一个上做的工作都会影响另一个,而且也使其受益。
让两种产品在不同环境下运行(32位Visual Studio与64位Rider)也会带来好处。
对于在ReSharper和Rider中存在的任何关于性能和内存的问题,在Rider中都可以保持不被注意到,但在ReSharper中会清晰地浮出水面。
修复程序总是让两者受益。
ReSharper和Rider面向同样的.NET开发人员,而我们希望给他们提供选择。
有的人喜欢Visual Studio和ReSharper/ReSharper旗舰版,而有的喜欢Rider。
我们欢迎团队在混合环境中工作,其中一些人可能使用标准版Visual Studio,另一些人在Visual studio中使用ReSharper旗舰版,还有的则使用Rider。
结论
在本文中,我们确定了像Visual Studio这样的IDE和像ReSharper这样的工具本质上都很复杂。
我们回顾了这两种产品的一些历史,并了解到其中一些历史不容易改变。但这并不意味着无法改进!
在下一篇博文中,我们会讲述为了提高ReSharper的质量和速度,JetBrains正在进行的一系列高水平的改进。而且,答案并非切换到Roslyn这样简单……敬请关注更多!
同时,如果您遇到性能问题,切记查看Visual Studio性能指南 (ReSharper 2017.3+),还有我们的知识库文章加快ReSharper(和Visual Studio)。 如果您遇到可以重现的具体的性能问题,而且您愿意<0>收集并发送性能问题快照给我们,我们将深表感激。
PS:也许您同样会乐于了解一下我们的Rider开发团队Leader Kirill Skrygan的演讲 “.NET Performance Issues and Optimizations in Visual Studio / Roslyn / ReSharper / Rider” 。
博客文章ReSharper性能简介系列将在.NET工具博客上首发,原作者Maarten Balliauw。