为什么JIT在这种情况下不使用readonly标志进行优化?

时间:2014-07-17 15:08:46

标签: c#

我有一个由此CachePage类数组组成的调用站点缓存。缓存页面有一个readonly标记数组,用于确定此页面是否正确使用。

internal class CachePage
{
    internal CachePage(Token[] tokens)
    {
        this.tokens = tokens;
    }
    private readonly Token[] tokens;
    // other members don't matter...

为了简化问题,在课堂上我有几个CheckTokens方法,它们采用了不同数量的参数,WLOG都是这样的。

public bool CheckTokens(Token g0, Token g1, Token g2)
{
    return (g2 == tokens[2] && g1 == tokens[1] && g0 == tokens[0]);
}

我向后遍历数组的元素,只产生一个绑定检查。或者我想。当我查看反汇编的输出时,我实际上看到每次比较它实际上都在执行边界检查。

但是,如果我像这样更改方法,则会消除额外的边界检查。

public bool CheckTokens(Token g0, Token g1, Token g2)
{
    var t=tokens;
    return (g2 == t[2] && g1 == t[1] && g0 == t[0]);
}

为什么要添加额外的绑定检查?没有readonly标志告诉JIT这个私有变量不能被变异吗?

这是一个低级缓存,所以花在确定这条路径是否越好的时间越少越好。

编辑: 这是针对rbitJIT和普通JIT尝试的64位.net 4.5。

1 个答案:

答案 0 :(得分:1)

我在实时交易的世界里工作,并在尝试从应用程序中挤出最后一点性能时对此进行调查。

正如汉斯在问题评论中所说,JITters选择忽略了一些优化。其中之一是注册readonly个成员变量,这些变量在方法中被多次读取。虽然从概念上讲这似乎是一个简单的实现,但是认识到多次读取相同的成员变量并非易事。

简单地说,这是一种权衡,在绝大多数情况下,潜在的好处并不值得JITter付出代价。如果您的性能调优已达到微优化的程度,那么明确启用JITter以通过手动将其提升为局部变量来注册成员变量。这可以使JITter执行其他优化,例如消除边界检查。