28

我正在编写一个 XNA 游戏,我在其中进行逐像素碰撞检查。检查这一点的循环是通过移位一个 int 和按位 ORing 来实现的,通常难以阅读和理解。

我想添加私有方法,例如private bool IsTransparent(int pixelColorValue)使循环更具可读性,但我不想要方法调用的开销,因为这是对性能非常敏感的代码。

有没有办法强制编译器内联这个调用或者我会这样做我只是希望编译器会做这个优化?

如果没有办法强制这样做,有没有办法检查该方法是否内联,而不是阅读反汇编?如果该方法被内联并且不存在其他调用者,它会在反射中显示吗?

编辑:我不能强迫它,所以我可以检测到它吗?

4

10 回答 10

27

不,你不能。更重要的是,决定内联的不是 VS 编译器,它接收你的代码并将其转换为 IL,而是 JIT 编译器,它接收 IL 并将其转换为机器代码。这是因为只有 JIT 编译器对处理器架构有足够的了解,才能决定将方法内联是否合适,因为它是指令流水线和缓存大小之间的权衡。

因此,即使查看 .NET Reflector 也无济于事。

于 2009-03-05T21:56:50.393 回答
18

“您可以检查 System.Reflection.MethodBase.GetCurrentMethod().Name。如果方法是内联的,它将返回调用者的名称。”

——乔尔·科霍恩

于 2009-03-05T21:56:01.410 回答
16

在 .net 4.5 中有一种鼓励更积极内联的新方法,如下所述:http: //blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive-inlining-in-the -clr-4-5-jit.aspx

基本上它只是一个告诉编译器尽可能内联的标志。不幸的是,它在当前版本的 XNA (Game Studio 4.0) 中不可用,但当 XNA 今年某个时间赶上 VS 2012 时应该可用。如果您以某种方式在 Mono 上运行,它已经可用。

[MethodImpl(MethodImplOptions.AggressiveInlining)] 
public static int LargeMethod(int i, int j)
{ 
    if (i + 14 > j) 
    { 
        return i + j; 
    } 
    else if (j * 12 < i) 
    { 
        return 42 + i - j * 7; 
    } 
    else 
    { 
        return i % 14 - j; 
    } 
}
于 2012-03-20T17:48:45.493 回答
4

请注意,Xbox 的工作方式不同。

谷歌出现了这个:

“内联方法可减轻方法调用的开销。JIT 形成内联,满足以下条件。

  • IL 代码大小为 16 字节或更少。
  • 不使用分支命令(如果句子等)。
  • 不使用局部变量。
  • 未进行异常处理(try、catch 等)。
  • float 不用作方法的参数或返回值(可能由 Xbox 360 使用,未应用)。
  • 当一个方法中有两个或多个参数时,它用于声明的轮次。

但是,虚函数不会形成内联函数。”

http://xnafever.blogspot.com/2008/07/inline-method-by-xna-on-xbox360.html

我不知道他是否正确。任何人?

于 2009-03-06T11:57:00.653 回答
1

不,你不能。

基本上,您也不能在大多数现代 C++ 编译器中这样做。inline只是对编译器的一个提议。接受与否是自由的。

C# 编译器不会在 IL 级别执行任何特殊的内联。JIT 优化器就是这样做的。

于 2009-03-05T21:51:19.733 回答
1

为什么不使用不安全的代码(已知的内联 c)并使用 c/c++ 样式指针,这对 GC 是安全的(即不受收集影响),但有其自身的安全隐患(不能用于 Internet 区域应用程序)但是对于您想要实现的那种东西来说非常棒,尤其是在性能方面,尤其是在数组和按位运算方面?

总而言之,您想要应用程序的一小部分性能?使用不安全的代码并使用指针等对我来说似乎是最好的选择

编辑:有点首发? http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

于 2009-03-05T23:01:19.740 回答
1

检查这一点的唯一方法是获取或编写探查器,并挂钩到 JIT 事件,您还必须确保在探查时默认情况下没有关闭内联。

于 2009-03-06T12:04:08.530 回答
0

您可以在运行时使用前面提到的 GetCurrentMethod 调用来检测它。但是,这似乎有点浪费[1]。最简单的事情就是只 ILDASM 和 MSIL 并在那里检查。

请注意,这专门用于编译器内联调用,并在 MSDN 上的各种反射文档中进行了介绍。

如果调用 GetCallingAssembly 方法的方法被编译器内联扩展(即,如果编译器将函数体插入到发出的 Microsoft 中间语言 (MSIL) 中,而不是发出函数调用),则 GetCallingAssembly 返回的程序集方法是包含内联代码的程序集。这可能与包含原始方法的程序集不同。要确保调用 GetCallingAssembly 方法的方法不被编译器内联,您可以使用 MethodImplOptions.NoInlining 应用 MethodImplAttribute 属性。

然而,JITter 也可以自由地内联调用——但我认为反汇编器将是验证在该级别上做了什么和没有做什么的唯一方法。

编辑:为了澄清这个线程中的一些混乱,csc.exe内联 MSIL 调用- 尽管 JITter 将(可能)在其中更具侵略性。

[1] 而且,浪费 - 我的意思是 (a) 由于反射查找,它破坏了内联的目的(更好的性能)。并且(b),它可能会改变内联行为,使其不再内联。而且,在您认为您可以使用 Assert 或其他东西打开它之前 - 请意识到它不会在 Debug 期间内联,但可能在 Release 中。

于 2009-03-05T22:03:55.197 回答
0

有没有办法强制编译器内联这个调用或者我会这样做我只是希望编译器会做这个优化?

如果内联函数更便宜,它会。所以不要担心它,除非你的分析器说它确实是一个问题。

了解更多信息

.NET 3.5 SP1 中的 JIT 增强功能

于 2009-03-06T00:07:22.607 回答
0
于 2019-03-02T23:37:10.487 回答