我正在使用Red Gate的性能分析器优化物理模拟程序。代码中的一部分涉及碰撞检测,其中包含大约52个类似以下的小型检查,处理3维空间中26个方向上的单元格,在两种情况下。
CollisionPrimitiveList cell = innerGrid[cellIndex + 1];
if (cell.Count > 0)
contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);
cell = innerGrid[cellIndex + grid.XExtent];
if (cell.Count > 0)
contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);
cell = innerGrid[cellIndex + grid.XzLayerSize];
if (cell.Count > 0)
contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);
作为程序中一个非常紧密的循环,所有这些代码都必须在同一个方法中,但是我发现,在我将区域从二维扩展到三维后(将检查次数从16增加到52),突然间,即使它只是一个简单的getter,cell.Count也不再被内联。
public int Count { get { return count; } }
这导致了巨大的性能损失,并且花费了我相当长的时间才发现,当cell.Count出现在方法中不超过28次时,每次都会被内联,但一旦出现在方法中29次或更多次时,它就再也没有被内联过(尽管大部分调用来自极限情况下的代码部分,这些部分很少被执行)。所以回到我的问题,有人有任何想法来避免这个限制吗?我认为简单的解决方案就是将count字段设置为internal而不是private,但我想要更好的解决方案,或者至少对这种情况有更好的理解。我希望微软的编写高性能托管应用程序页面上http://msdn.microsoft.com/en-us/library/ms973858.aspx提到了这种情况,但可悲的是它没有(可能是因为28次的限制有多么随意)。
我使用的是.NET 4.0。
编辑:看起来我误解了我的小测试。我发现内联失败并不是由于方法本身被调用了28次以上,而是因为它们应该内联到的方法“太长”了,按照某些标准。这仍然让我感到困惑,因为我不明白一个简单的getter如何会被合理地拒绝内联(并且我的分析器清楚地告诉我,在它们内联之后性能显着提高),但显然CLI JIT编译器拒绝内联任何东西,只是因为方法已经很大了(通过微小变化进行的测试表明,这个限制是1500行代码大小(从idasm中),超过它就不再内联,即使在我的getter情况下也是如此,一些测试表明,它们内联时不会增加任何额外的代码开销)。
谢谢。