为什么WinDbg将System.Int32变量显示为24个字节?

时间:2016-06-27 14:26:02

标签: c# .net debugging windbg

我正在使用WinDbg分析.NET进程的内存转储,我注意到它报告堆上所有System.Int32变量的大小为 24字节。以下是其中一个变量的相关DumpObj调用示例:

0:000> !DumpObj /d 00000061c81c0e80
Name:        System.Int32
MethodTable: 00007fff433f37c8
EEClass:     00007fff42e30130
Size:        24(0x18) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007fff433f37c8  4000456        8         System.Int32  1 instance              141 m_value

据我所知,System.Int32的大小应该是4个字节。这种差异的根源是什么?

2 个答案:

答案 0 :(得分:3)

堆上的任何对象都有开销。在32位MS.NET运行时,这是8个字节,在64位,16个字节(免责声明:这不是严格的合同,可能在将来或在符合要求的实现中更改一个.NET运行时)。

由于您的int已装箱,因此会产生16字节的开销。所以你可能期望总共使用20个字节。好吧,除了在64位系统上,对象(和结构)被填充到8字节边界,所以实际上每int个24字节。

相反,当你使用带有16个整数的struct时,你只能使用16 + 4 * 16 = 80字节的内存,每个整数总共5个字节。

同样,大部分内容都是一个实现细节,所以不是你可以依赖的东西;如果有效的.NET运行时完全有可能在1 MiB的内存中存储单个int,并且它也可以将它存储在一些紧凑的表示中或者使用interning,只要它符合所有合同行为的类型。与实际的MS运行时实现相比,它也非常简化 - 例如,如果您的对象变得足够大,则需要更多的开销。

答案 1 :(得分:2)

它不是int32的大小做dd或dq地址并且看到你的int32卡在第二个dword或qword中 对于x86 / x64,每个对象的隐含开销为12个字节或24个字节

0:004> .shell -ci "!DumpObj /d 01c72360" grep -i size
    Size:        12(0xc) bytes
    .shell: Process exited
    0:004> dd 01c72360 l4
    01c72360  5890c770 000001b5 80000000 5890afb0
    0:004> .shell -ci "!DumpObj /d 01c72360" grep -i method
    MethodTable: 5890c770
    .shell: Process exited
    0:004> .shell -ci "!DumpObj /d 01c72360" grep -i value
          MT    Field   Offset                 Type VT     Attr    Value Name
    5890c770  400044f        4         System.Int32  1 instance      437 m_value
    .shell: Process exited
    0:004> ? 1b5
    Evaluate expression: 437 = 000001b5

将int32分开让我们在x86中解析一个宽字符串“stream”

actualsizereqdfor(L"stream\0") = 7 * sizeof(wchar_t) == 7 * 2  == 0n14;    
sizeof(method table )                                          == 0n04;   
sizeof(sizeof(L"stream))                                       == 0n04;    
sizeof(padding ?? terminator ?? whatever ?? )                  == 0n04;   
so total size                                                  == 0n26
dumpobj的结果

0:004> !DumpObj /d 01c73ad0
Name:        System.String
MethodTable: 5890afb0

Size:        26(0x1a) bytes

String:      stream
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
5890c770  40000aa        4         System.Int32  1 instance        6 m_stringLength
5890b9a8  40000ab        8          System.Char  1 instance       73 m_firstChar
5890afb0  40000ac        c        System.String  0   shared   static Empty

原始显示

0:004> db 01c73ad0 l1a
01c73ad0  b0 af 90 58 06 00 00 00-73 00 74 00 72 00 65 00  ...X....s.t.r.e.
01c73ae0  61 00 6d 00 00 00 00 00-00 00                    a.m.......