2

更新我的一些代码示例以进行培训我注意到以前由CLR保持未初始化的一些本地内存现在正在归零

这是一个显示“问题”的小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
    

我很好奇这种实现更改背后的基本原理。

因此,欢迎任何反馈,尤其是来自内部人员的反馈,或对任何文章的引用,或者更好的是对规范的引用。:)

提前致谢。

4

1 回答 1

2

这只是一个巧合,没有什么可以故意清除您的当地人。Jitter 试图将本地变量保存在寄存器中,如果没有必要,它甚至不会分配堆栈空间。您的程序很小,当您不使用 /32bitpreferred 标志编译它时,它很可能为您的本地选择一个寄存器,该寄存器以前在当前线程上没有使用过,并且仍然具有零值。您可以在以下情况下取回您的垃圾:

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

与以前的版本相比,我不确定为什么您需要付出更多努力才能在 4.5 版中查找未初始化的值。也许这是抖动某些变化的副作用,但我只是猜测。关键是您仍然需要本地人的 init 标志来确保他们获得零初始值。

于 2015-05-08T16:16:17.347 回答