7

我正在查看带有 Reflector 的Roslyn 2012 年 9 月 CTP,我注意到 SlidingTextWindow 类具有以下内容:

internal sealed class SlidingTextWindow : IDisposable
{
    private static readonly ConcurrentQueue<char[]> arrayPool = new ConcurrentQueue<char[]>();
    private int basis;
    private readonly LexerBaseCache cache;
    private char[] characterWindow;
    private int characterWindowCount;
    private int characterWindowStart;
    private int offset;
    private readonly IText text;
    private readonly int textEnd;

    public SlidingTextWindow(IText text, LexerBaseCache cache)
    {
        this.text = text;
        this.basis = 0;
        this.characterWindowStart = 0;
        this.offset = 0;
        this.textEnd = text.Length;
        this.cache = cache;
        if (!arrayPool.TryDequeue(out this.characterWindow))
        {
            this.characterWindow = new char[2048];
        }
    }

    public void Dispose()
    {
        arrayPool.Enqueue(this.characterWindow);
        this.characterWindow = null;
    }

    // ...
}

我相信这个类的目的是提供对输入文本子字符串的快速访问,通过使用char[] characterWindow,一次从 2048 个字符开始(尽管characterWindow可能会增长)。我相信这是因为获取字符数组的子字符串比获取字符串更快,正如 Eric Lippert似乎在他的博客上指出的那样

SlidingTextWindow每次实例化类Lexer时都会实例化该类,每次调用SyntaxTree.ParseText.

我不明白该arrayPool领域的目的。它在此类中的唯一用途是在构造函数和 Dispose 方法中。调用SyntaxTree.ParseText时,似乎只有一个类的实例Lexer和创建的类的实例SlidingTextWindow。通过在处理实例时将其入队并在创建实例时characterWindow尝试使 a 出队可以获得什么优势?characterWindow

也许罗斯林团队的某个人可以帮助我理解这一点?

4

1 回答 1

17

优点是降低了收集压力,这对整体性能有积极影响。

.NET 垃圾收集器当然是一个通用的垃圾收集器。编译器和 IDE 的分配和对象生存期模式与一般的业务线应用程序完全不同,它们往往会以不同寻常的方式对 GC 施加压力。

如果您查看整个 Roslyn,就会发现很多地方都缓存了小型数组并在以后重新使用,而不是让 GC 将它们识别为短暂的垃圾并立即回收它们。经验实验表明,这可以显着提高性能。

我不建议在您自己的应用程序中这样做,除非您的分析表明您在收集压力方面存在可衡量的性能问题。对于绝大多数应用程序,GC 进行了很好的调整,池化策略的好处不值得付出可观的成本。

于 2013-08-25T14:42:36.940 回答