找出.net对象的大小

时间:2008-11-27 15:38:11

标签: .net memory-management garbage-collection profiling

我试图找出我的对象需要多少内存才能看到它们中有多少内存在大对象堆上(超过85,000字节)。

对于每个对象的任何引用类型等添加4为int,8为长,4(或8如果你在64位),或者是方法,属性等的开销是这么简单吗?

7 个答案:

答案 0 :(得分:52)

不要忘记实际对象的大小不包括它引用的任何对象的大小。

唯一可能最终出现在大对象堆上的东西是数组和字符串 - 其他对象本身往往相对较小。即使是具有(例如)10个引用类型变量(x86上各4个字节)和10个GUID(每个16字节)的对象也只占用大约208个字节(类型引用和同步块有一些开销)。

同样在考虑数组的大小时,不要忘记如果元素类型是引用类型,那么只有引用的大小才能计算数组本身。换句话说,即使你有一个包含20,000个元素的数组,数组对象本身的大小也只会超过80K(在x86上),即使它引用了更多的数据。

答案 1 :(得分:35)

请按照以下步骤获取对象的大小。

1)转到Visual Studio(2010)项目属性 - >调试选项卡 - >启用非托管代码调试。

2)转到Visual Studio Debug菜单 - >选项和设置 - >调试 - >符号。

3)启用Microsoft Symbol Server,保留默认值。(符号可以开始下载)

4)在代码中设置断点,开始调试(F5)。

5)打开调试 - > Windows - >立即窗口。

6)输入.load sos.dll(罢工之子)

7)输入!DumpHeap -type MyClass(你要查找的对象大小)

8)从输出位置找到对象的地址,即(00a8197c)

地址MT大小 00a8197c 00955124 36

9)接下来,!ObjSize 00a8197c

10)你去了 - > sizeof(00a8197c)= 12(0x48)字节(MyClass)

答案 2 :(得分:9)

您正在进入高级.NET调试领域。从John Robins debugging books开始。

WinDBG与Sos.dll(.NET发行版的一部分)和Sosex.dll扩展名一起使用。使用这些工具,您可以真正看到应用程序运行时发生的情况。您将找到上述问题的答案。

(另一个建议是安装Shared Source CLI 2.0,又称转子2,看看幕后发生了什么。)

答案 3 :(得分:9)

如果可以 - 序列化它!

Dim myObjectSize As Long

Dim ms As New IO.MemoryStream
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
bf.Serialize(ms, myObject)
myObjectSize = ms.Position

答案 4 :(得分:5)

Gomes的方法简化了:

  1. 转到Visual Studio(2010)项目属性 - >调试选项卡 - >启用非托管代码调试。

  2. 在代码中设置断点,开始调试(F5)。

  3. 打开调试 - > Windows - >立即窗口。

  4. 输入.load sos

  5. 输入(用对象名称替换myObject)

  6.   

    ?   的String.Format( “{0:X}”,Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc( myObject的)GetHandleValue())的ToString())    - 4)

    6.使用结果作为参数!ObjSize

    请参阅:SOS.DLL, object Address and Visual Studio debugger Introduction

    示例(我们正在寻找名为tbl的对象):

    .load sos
    extension C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll loaded
    ? string.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc(tbl).GetHandleValue()).ToString())-4)
    "27ccb18"
    !ObjSize 27ccb18
    PDB symbol for clr.dll not loaded
    sizeof(027ccb18) =       154504 (     0x25b88) bytes (System.Data.DataTable)
    

答案 5 :(得分:4)

除非它是一个巨大的值类型或实例类型(即数千个字段),否则您需要担心的唯一类型是大型数组或字符串。当然,要弄清楚数组的大小,您需要知道元素大小。

.NET(当前)对齐类型的方式与本机编译器对齐类型的方式大致相同。基本类型具有自然对齐,通常是两个最接近其大小的四舍五入的整数幂:

Single, Int32, UInt32 - 4
IntPtr, UIntPtr, pointers, references  - 4 on 32-bit, 8 on 64-bit
Double, Int64, UInt64 - 8
Char, Int16, UInt16   - 2
Byte, SByte           - 1

组装类型时,编译器将确保任何给定类型的所有字段在实例中的起始偏移量与对应于该类型的边界对齐 - 假设未使用显式布局。

用户定义的类型本身具有一个对齐方式,它是按任何字段类型的最高对齐方式计算的。如果需要,可以扩展类型的大小,以使类型的大小也对齐。

但是,当然,所有引用类型在大小和对齐方面仍然只是IntPtr.Size,因此引用类型的大小不会影响该类型的数组。

请注意,CLR可以根据自己的判断选择与上述不同的布局类型,可能会增加缓存局部性或减少对齐所需的填充。

答案 6 :(得分:0)

作为估计(2017年),您可以调试应用程序,在字典生效前设置断点,使用“内存使用快照”(选项卡:诊断工具下的内存使用情况),填写字典并获取另一个字典快照 - 不完全是一个很好的gestimate。