2013-09-29 42 views
2

更新一些我的代码示例进行培训我已经注意到一些以前未被CLR未初始化的本地内存现在是归零为什么在.Net 4.5中更改内存初始化规则?

这里是一个小CIL示例,演示了 “问题”:

.assembly Test{} 

.assembly extern mscorlib{} 

.class S extends [mscorlib]System.ValueType 
{ 
    .field public int32 n; 
} 

.method static void F() 
{ 
    .locals (int32, valuetype S) 

    ldloc 0 
    call void [mscorlib]System.Console::WriteLine(int32) 

    ldloca 1 
    ldfld int32 S::n 
    call void [mscorlib]System.Console::WriteLine(int32) 

    ret 
} 

.method static void Main() 
{ 
    .entrypoint 

    .locals (int32, valuetype S) 

    ldloc 0 
    call void [mscorlib]System.Console::WriteLine(int32) 

    ldloca 1 
    ldfld int32 S::n 
    call void [mscorlib]System.Console::WriteLine(int32) 

    call void F() 

    ret 
} 

这里是输出:

  • NET 2.0(我几乎可以肯定它与.Net 4.0相同):

    $ /Windows/Microsoft.NET/Framework/v2.0.50727/ilasm.exe Test.il 
    
    Microsoft (R) .NET Framework IL Assembler. Version 2.0.50727.5420 
    Copyright (c) Microsoft Corporation. All rights reserved. 
    Assembling 'Test.il' to EXE --> 'Test.exe' 
    Source file is ANSI 
    
    Assembled global method F 
    Assembled global method Main 
    Creating PE file 
    
    Emitting classes: 
    Class 1:  S 
    
    Emitting fields and methods: 
    Global Methods: 2; 
    Class 1 Fields: 1; 
    Resolving local member refs: 3 -> 3 defs, 0 refs, 0 unresolved 
    
    Emitting events and properties: 
    Global 
    Class 1 
    Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved 
    Writing PE file 
    Operation completed successfully 
    Test.il(6) : warning -- Non-sealed value class, made sealed 
    
    $ ./Test.exe 
    211384 
    0 
    2157704 
    2157328 
    
  • .net 4.5:

    $ /Windows/Microsoft.NET/Framework/v4.0.30319/ilasm.exe Test.il 
    
    Microsoft (R) .NET Framework IL Assembler. Version 4.0.30319.17929 
    Copyright (c) Microsoft Corporation. All rights reserved. 
    Assembling 'Test.il' to EXE --> 'Test.exe' 
    Source file is ANSI 
    
    Assembled global method F 
    Assembled global method Main 
    Creating PE file 
    
    Emitting classes: 
    Class 1:  S 
    
    Emitting fields and methods: 
    Global Methods: 2; 
    Class 1 Fields: 1; 
    Resolving local member refs: 3 -> 3 defs, 0 refs, 0 unresolved 
    
    Emitting events and properties: 
    Global 
    Class 1 
    Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved 
    Writing PE file 
    Operation completed successfully 
    Test.il(6) : warning : Non-sealed value class, made sealed 
    
    $ ./Test.exe 
    0 
    0 
    0 
    0 
    

我很好奇这背后实施变革的理由。

因此,欢迎任何反馈意见,尤其是来自内部人员,或对任何文章或更好的参考文献的参考。 :)

在此先感谢。

+1

这几乎可以肯定地在CIL运行时规范中。你看过那里吗?将字段归零而不是未初始化字段几乎肯定比获取随机结果更可取。那里不需要太多理由。 –

+0

在ECMA-335标准中,我看到“如果指定了init,变量将根据它们的类型初始化为其默认值:参考 类型被初始化为空,并且值类型被清零。但是这里没有“init”。 – Pragmateek

+3

我怀疑Microsoft最初是否将变量初始化为语言编译器的决定。但是由于像你这样的人正在更频繁地挖掘真正的IL,并且IL程序和C#程序一样有效,所以将初始化重新推回到IL中是有意义的。 –

回答

2

这只是一个巧合,没有任何东西会故意清除你的本地人。抖动试图将你的本地人保存在寄存器中,如果没有必要,它甚至不会分配堆栈空间。你的程序很小,当你不用/ 32bit优先标记进行编译时,选择本地寄存器的可能性很大,这个寄存器在当前线程中没有被使用过,并且仍然没有值。当你:

  • 用/ 32bit优先标记编译代码。 32位代码具有较少的寄存器,因此您的本地可能存储在脏堆栈或脏寄存器中。
  • 为您的值类型创建更多的字段,或者使用更多的本地语言,因此它们不适合寄存器集,或者抖动不选择将它们存储在那里。
  • 做更多的事情在你的方法是什么涉及寄存器

我不知道为什么你需要做出更多的努力相比以前的版本4.5版找到未初始化值。也许这是抖动的一些变化的副作用,但我只是猜测。重点是你仍然需要在你的本地人的初始化标志,以确保他们得到零初始值。