作为MSIL和Java字节码之间的差异问题的一种跟进?,Java虚拟机的工作方式(主要)差异或相似之处是什么?.NET Framework 公共语言运行时(CLR)有效吗?
还有,是 .NET框架 CLR是"虚拟机"还是没有虚拟机的属性?
我今天正在研究一个项目,发现自己在几个地方使用Math.Max,并在其他地方使用内联if语句.所以,我想知道是否有人知道哪个更"好"......或者更确切地说,真正的差异是什么.
例如,在下面,c1 = c2:
Random rand = new Random();
int a = rand.next(0,10000);
int b = rand.next(0,10000);
int c1 = Math.Max(a, b);
int c2 = a>b ? a : b;
Run Code Online (Sandbox Code Playgroud)
我是专门询问C#,但我想不同语言的答案可能会有所不同,但我不确定哪些有类似的概念.
我正在写一个XNA游戏,我在那里进行逐像素碰撞检查.通过移位int和按位ORing来检查这种情况的循环通常难以阅读和理解.
我想添加私有方法,例如private bool IsTransparent(int pixelColorValue)使循环更具可读性,但我不希望方法调用的开销,因为这是性能敏感的代码.
有没有办法强制编译器内联这个调用,或者我是否只是希望编译器会进行这种优化?
如果没有办法强制执行此操作,是否有办法检查方法是否内联,而不是读取反汇编?如果内联并且没有其他调用者存在,该方法是否会显示在反射中?
编辑:我不能强迫它,所以我可以检测到它吗?
似乎我遇到的每个帖子都达成了相同的共识:仅返回字段的属性由JIT内联,并且具有与字段几乎相同的性能.
但是,我目前的情况似乎并非如此.我的程序进行密集计算,访问许多属性,这些属性只是自动获取器和私有设置器.但是,在这种特殊情况下,我只是复制一个对象.
在启用优化的情况下在发布模式下分析代码会导致get对属性函数的许多调用.Copy()总呼叫总计约5.6ms.
但是,当属性转换为字段时,函数运行速度比使用属性快6倍:
与使用字段相比,比较两个属性的相等性似乎会产生更多的性能损失.这是类IEquatable实现的基准,使用相同的代码,但使用字段交换属性.
如果JIT应该通过内联来优化属性,为什么会出现?我想保留属性,因为它们的访问控制方面非常方便,但如果它们这么慢,我会坚持使用字段.
编辑:似乎受此问题影响的一些(但不是全部)案例正在使用在接口中声明的属性.在这些情况下没有使用其他多态性,但在这些情况下,删除接口会将性能差异带入预期的水平.
编辑2:如前面的编辑所述,似乎问题的一部分是由于接口虚拟调用.经过更多调查后,似乎在CLR中运行基准测试正确地内联属性,但JetBrains dotTrace没有,即使选中"启用内联"也是如此.
我编写了一个logger/exceptionfactory模块,它使用System.Diagnostics.StackTrace来获取调用方法及其声明类型的属性.但是我注意到,如果我在发布模式下运行Visual Studio之外的代码,我的一些较短的方法会在堆栈跟踪中内联并丢失.现在我无法测试一个方法是否会在运行时内联,但我不想要[MethodImpl(MethodImplOptions.NoInlining)]每个重要的方法.但是如果我的基类中的方法因此而丢失,我可能会误读层和操作信息,这可能导致错误的日志或错误参数化的异常.
是否有一条经验法则是何时何地内联?虚方法,静态方法,基类方法是否有任何不同?我只需要担心内部装配内联吗?内部名称空间
关于C#的几个问题
我缺少严肃的优化,因为JIT不会内联我的很多方法.
例如,让我们有以下代码:
static void Main(string[] args)
{
IsControl('\0');
}
public static bool IsControl(char c)
{
return ((c >= 0 && c <= 31) || (c >= 127 && c <= 159));
}
Run Code Online (Sandbox Code Playgroud)
在JIT编译之后生成以下内容:
0000001f xor ecx,ecx
00000021 call FFFFFFFFFFEC9760
00000026 mov byte ptr [rsp+20h],al
0000002a nop
0000002b jmp 000000000000002D
0000002d add rsp,38h
00000031 rep ret
Run Code Online (Sandbox Code Playgroud)
请注意,这0000001f是我设置断点的地方.你可以看到有一个电话00000021,这是绝对错误的.为什么这么小的方法不适合内联?对于注释,这是在优化的基础上编译的.
c# ×6
inline ×4
.net ×3
jit ×2
optimization ×2
attributes ×1
bytecode ×1
cil ×1
compilation ×1
field ×1
inline-if ×1
java ×1
logging ×1
performance ×1
properties ×1