经常调用的方法中的新临时变量

时间:2014-08-05 18:13:39

标签: c# garbage-collection garbage

更有效地在经常调用的方法中设置新的临时变量吗? (> 1000x s)

这是一个当前的例子。我指定了3个新的整数值,而不是将这些值直接传递给另一个方法。

// What I'm currently doing
public virtual byte GetByte(Vector3 worldPos) {
    worldPos -= transform.position;
    int x = Mathf.FloorToInt(worldPos.x);
    int y = Mathf.FloorToInt(worldPos.y);
    int z = Mathf.FloorToInt(worldPos.z);
    return GetByte(x, y, z);
}

但直接传递这些值会更有效,而不是分配3个新变量吗?

// would this be more efficient?
public virtual byte GetByte(Vector3 worldPos) {
    worldPos -= transform.position;
    return GetByte(
        Mathf.FloorToInt(worldPos.x),
        Mathf.FloorToInt(worldPos.y),
        Mathf.FloorToInt(worldPos.z));
}

2 个答案:

答案 0 :(得分:5)

没有区别。局部变量被添加到堆栈中。并且用作函数参数的值也会添加到堆栈中。因此,在这两种情况下,都会向堆栈添加相同的内容。

所以只要使用你认为更具可读性的东西。

答案 1 :(得分:2)

它们会导致生成不同的IL。

当前(使用int x = Mathf.FloorToInt(worldPos.x); ...):

.method public hidebysig newslot virtual instance uint8 GetByte1 (
        valuetype ConsoleApplication5.Vector3 worldPos
    ) cil managed 
{
    .locals init (
        [0] int32 x,
        [1] int32 y,
        [2] int32 z
    )

    IL_0000: ldarga.s worldPos
    IL_0002: ldfld int32 ConsoleApplication5.Vector3::x
    IL_0007: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_000c: stloc.0
    IL_000d: ldarga.s worldPos
    IL_000f: ldfld int32 ConsoleApplication5.Vector3::y
    IL_0014: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_0019: stloc.1
    IL_001a: ldarga.s worldPos
    IL_001c: ldfld int32 ConsoleApplication5.Vector3::z
    IL_0021: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_0026: stloc.2
    IL_0027: ldarg.0
    IL_0028: ldloc.0
    IL_0029: ldloc.1
    IL_002a: ldloc.2
    IL_002b: call instance uint8 ConsoleApplication5.X::GetByte(int32,  int32,  int32)
    IL_0030: ret
}

替代:

.method public hidebysig newslot virtual instance uint8 GetByte2 (
        valuetype ConsoleApplication5.Vector3 worldPos
    ) cil managed 
{
    IL_0000: ldarg.0
    IL_0001: ldarga.s worldPos
    IL_0003: ldfld int32 ConsoleApplication5.Vector3::x
    IL_0008: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_000d: ldarga.s worldPos
    IL_000f: ldfld int32 ConsoleApplication5.Vector3::y
    IL_0014: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_0019: ldarga.s worldPos
    IL_001b: ldfld int32 ConsoleApplication5.Vector3::z
    IL_0020: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_0025: call instance uint8 ConsoleApplication5.X::GetByte(int32,  int32,  int32)
    IL_002a: ret
}

理论上,替代可以更高效,因为它不会产生从局部变量存储和检索int值的成本,因此执行该方法所需的指令较少。但是,代码MSIL在运行时仍然会被JIT,并且可能会根据它的优化方式而结束。

我会坚持使用当前版本,因为它可以使调试更容易,因为您可以通过检查变量来查看FloorToInt调用的结果。

唯一可以确定的方法是对代码进行基准测试,虽然这是一个相当无意义的优化问题,但可能有更好的方法来加速您的应用程序!