0

在 C# 中,为两种不同的编写方式生成的字节码是否有任何差异,我期望是同一件事:

返回创建的对象:

public MemoryStream GetStream() {
  MemoryStream s = new MemoryStream(this.GetBytes());
  return s;
}

返回新:

public MemoryStream GetStream() {
  return new MemoryStream(this.GetBytes());
}

是否会优化任何差异?还是第一个比第二个更容易受到垃圾收集的影响?或者这只是个人喜好?

4

4 回答 4

1

看IL代码,好像第二个版本的步骤比第一个少。

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream1 () cil managed 
{
    // Method begins at RVA 0x22c0
    // Code size 13 (0xd)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s,
        [1] class [mscorlib]System.IO.MemoryStream CS$1$0000
    )

    IL_0000: nop
    IL_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: stloc.1
    IL_0009: br.s IL_000b

    IL_000b: ldloc.1
    IL_000c: ret
} // end of method Form1::GetStream1

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream2 () cil managed 
{
    // Method begins at RVA 0x22dc
    // Code size 11 (0xb)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream CS$1$0000
    )

    IL_0000: nop
    IL_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0006: stloc.0
    IL_0007: br.s IL_0009

    IL_0009: ldloc.0
    IL_000a: ret
} // end of method Form1::GetStream2

看起来它并没有做更多的事情,但还是多走了几步。

@Alexei Levenkov,这是代码的发布版本

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream1 () cil managed 
{
    // Method begins at RVA 0x2264
    // Code size 8 (0x8)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s
    )

    IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0005: stloc.0
    IL_0006: ldloc.0
    IL_0007: ret
} // end of method Form1::GetStream1

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream2 () cil managed 
{
    // Method begins at RVA 0x2278
    // Code size 6 (0x6)
    .maxstack 8

    IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0005: ret
} // end of method Form1::GetStream2

似乎还是稍微多一点。

于 2013-06-28T07:38:29.277 回答
1

如果您使用 Reflector 检查为此生成的代码:

public MemoryStream GetStream(byte[] bytes)
{
    MemoryStream s = new MemoryStream(bytes);
    return s;
}

对于发布版本,您会得到:

.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s)
    L_0000: ldarg.1 
    L_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ret 
}

如您所见,C# 编译器已优化掉多余的变量。

但是,对于调试版本,您会得到以下信息:

.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s,
        [1] class [mscorlib]System.IO.MemoryStream CS$1$0000)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: stloc.1 
    L_000a: br L_000f
    L_000f: ldloc.1 
    L_0010: ret 
}

显然,如果您想在调试时检查它,编译器无法优化调试构建的额外变量。

因此,如果您想保留额外的变量以进行调试,那很好 - 它对发布版本没有影响。

于 2013-06-28T07:40:25.387 回答
1

我相信生成的优化 JITed 代码将是相同的。

对 GC 行为绝对没有影响,因为对象的生命周期将由使用返回值的人决定(您可能会考虑在函数结束之前不再使用值的情况,这显然不是这里的情况 -s直接返回方法执行结束)。

非优化(调试)构建中唯一明显的区别是您将能够看到s变量的值。

于 2013-06-28T07:40:43.117 回答
0

这两个代码片段大部分相同,性能差异很小,可以忽略不计,从中选择代码样式和方法功能是一个问题。如果您的方法除了返回对象之外不应该做任何其他事情MemoryStream,那么第二个代码片段就足够了,但是如果您需要在MemoryStream返回对象之前对对象执行一些操作,则必须使用第一个。垃圾收集方面没有区别。

于 2013-06-28T07:39:52.330 回答