据我所知,Roslyn的预发布版本实现了不可变树,如Eric Lippert在this excellent blog post中所述。但是,该帖子的结尾是:
"成本是这个系统很复杂,如果" red"可能会耗费大量内存。外墙变得很大。我们目前正在做实验,看看我们是否可以在不损失收益的情况下降低部分成本。"
我想问一下发布版本的结果。我已经开始检查Roslyn sources,但代码相当复杂。
我感兴趣的是关于上述费用的低级别设计结果。
答案 0 :(得分:8)
在这里讨论论坛上,VSadov对Roslyn的表现和不可变树的实现有了很好的了解:https://roslyn.codeplex.com/discussions/541953
在高层次上,他讨论了并发,绿色节点的重复数据删除,终端的重复数据删除以及这些树内字符串的重复数据删除。
他还谈到了红树的懒惰。不是在每次文本更改后计算红树,而是仅在有人请求时才计算红树。
最后,他讨论了红树以及它的弱点这一事实。我从未使用或看过WeakReference
类,而VSadov提供了如何在红树中使用它的很好的概述。基本上,允许垃圾收集器清理红树的部分,如果需要,可以在以后重新创建它们。我对实现并不熟悉,但Eric Lippert指出红树外观会导致大量内存占用。我想这些WeakReferences
可以在一定程度上缓解这个问题。
答案 1 :(得分:3)
目前我们仍在做与Eric所描述的基本相同的事情。我们尝试了一些实验,但发现API清晰度的成本太高而无法支付。相反,我们做的主要改变是通过将SyntaxToken
放入红色模型中的结构来减少堆分配和GC成本。这是一个显着的节省,因为在平均源文件中,语法树中大约一半的节点是终端(SyntaxToken
s)。绿色节点不是结构,但另一方面,由于它们不包含父指针或位置,因此它们被实现 - 我们为所有相同的节点(相同的琐事和文本)共享绿色节点的相同实例。
我不确定你的意思"成本"一个编辑。时间/空间/复杂的/ etc。一般来说,我们有一个增量词法分析器,可以重新扫描受编辑影响的区域。然后我们有一个增量解析器,在最好的情况下,重新分析与新的lexed标记相交的语句,然后重新构建" spine"绿树的树回到根,同时重新使用树中的其余绿色节点。根据定义,所有红色节点都不可重用。新树有一个新的根节点,可以从任何其他节点访问。
编译器中没有进行任何其他优化。我们在撤消后重新使用IDE中的缓存树,但我不确定。