找出 .NET 对象的大小

发布于 2024-07-09 15:55:03 字数 283 浏览 6 评论 0 原文

我试图找出我的对象占用了多少内存来查看其中有多少最终出现在 大型对象堆(超过 85,000 字节的任何内容)。

是不是像为每个对象添加 4(表示 int)、添加 8(表示 long)、添加 4(如果是 64 位,则添加 8)作为任何引用类型等那么简单,还是有方法、属性等的开销?

I'm trying to find out how much memory my objects take to see how many of them are ending up on the Large Object Heap (which is anything over 85,000 bytes).

Is it as simple as adding 4 for an int, 8 for a long, 4 (or 8 if you're on 64 bit) for any reference types etc for each object, or are there overheads for methods, properties, etc.?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

虐人心 2024-07-16 15:55:03

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

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

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

Don't forget that the size of an actual object doesn't include the size of any objects it references.

The only things which are likely to end up on the large object heap are arrays and strings - other objects tends to be relatively small in themselves. Even an object with (say) 10 reference type variables (4 bytes each on x86) and 10 GUIDs (16 bytes each) is only going to take up about 208 bytes (there's a bit of overhead for the type reference and sync block).

Likewise when thinking about the size of an array, don't forget that if the element type is a reference type, then it's only the size of the references that count for the array itself. In other words, even if you've got an array with 20,000 elements, the size of the array object itself will only be just over 80K (on x86) even if it references a lot more data.

牛↙奶布丁 2024-07-16 15:55:03

请按照以下步骤获取物体的尺寸。

  1. 转到 Visual Studio 2010 项目属性 → 调试选项卡 → 启用非托管代码调试

  2. 转到 Visual Studio“调试”菜单→“选项和设置”→“调试”→“符号”。

  3. 在那里,启用 Microsoft Symbol Server 并保留默认值(符号可能会开始下载)。

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

  5. 打开调试Windows立即窗口

  6. 输入.load sos.dllSon of Strike

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

  8. 从输出中找到该对象的地址,即(00a8197c)

    地址 MT 大小
    00a8197c 00955124 36

  9. 下一步,!ObjSize 00a8197c

  10. 就是这样 → sizeof(00a8197c) = 12 (0x48) 字节 (MyClass)

Please follow these steps to get the size of the object.

  1. Go to Visual Studio 2010 Project Properties → Debug tab → Enable unmanaged code debugging.

  2. Go to the Visual Studio Debug menu → Options and SettingsDebuggingSymbols.

  3. There, enable Microsoft Symbol Server and leave the default (symbols may start a download).

  4. Set the breakpoint in your code, start debugging (F5).

  5. Open DebugWindowsImmediate Window.

  6. Enter .load sos.dll (Son of Strike)

  7. Enter !DumpHeap -type MyClass (the object you want to find the size of)

  8. From the output, locate the address of the object, i.e. (00a8197c)

    Address MT Size
    00a8197c 00955124 36

  9. Next, !ObjSize 00a8197c

  10. There you go → sizeof(00a8197c) = 12 (0x48) bytes (MyClass)

好菇凉咱不稀罕他 2024-07-16 15:55:03

如果可以的话 - 将其序列化!

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

If you can - Serialize it!

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
柒夜笙歌凉 2024-07-16 15:55:03

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

WinDBG 与 Sos.dll(.NET 发行版的一部分)和 < a href="http://www.stevestechspot.com/SOSEXANewDebuggingExtensionForManagedCode.aspx" rel="noreferrer">Sosex.dll 扩展。 使用这些工具,您可以真正了解应用程序运行时发生的情况。 您将找到上述问题的答案。

(另一个建议是安装 共享源 CLI 2.0,又名 Rotor 2,了解幕后情况。)

You are getting into an area of advanced .NET debugging. Start with John Robins debugging books.

Use WinDBG with Sos.dll (part of .NET distribution) and Sosex.dll extensions. With these tools you can really see what's happening when your application is running. You will find answers to your above mentioned questions.

(Another recommendation would be to install Shared Source CLI 2.0, aka. Rotor 2, to see what's going on under the hood.)

往事随风而去 2024-07-16 15:55:03

戈麦斯的方法简化:

  1. Go到 Visual Studio (2010) 项目属性* → 调试选项卡 → 启用非托管代码调试

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

  3. 打开调试Windows立即窗口

  4. 输入.load sos

  5. 输入(将 myObject 替换为您的对象的名称)

    <块引用>


    String.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc(myObject).GetHandleValue()) .ToString())

      

  6. 将结果作为!ObjSize的参数

参见:SOS.DLL、对象地址和 Visual Studio 调试器
简介

示例(我们正在寻找名为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)

Gomes's method simplified:

  1. Go to Visual Studio (2010) Project Properties* → Debug tab → Enable unmanaged code debugging.

  2. Set the break point in your code, start debugging (F5).

  3. Open DebugWindowsImmediate Window.

  4. Enter .load sos

  5. Enter (replace myObject with the name of your object)

    ?
    String.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc(myObject).GetHandleValue()).ToString())

  6. Use the result as the parameter of !ObjSize

See: SOS.DLL, object Address and Visual Studio debugger
Introduction

Example (we are looking for object named 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)
与之呼应 2024-07-16 15:55:03

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

.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 可以自行决定选择与上述不同的布局类型,可能是为了增加缓存局部性或减少对齐所需的填充。

Unless it's a huge valuetype or instance type (i.e. many thousands of fields), the only types you need to worry about are large arrays, or strings. Of course, to figure out the size of an array, you need to know the element size.

.NET (currently) aligns types in much the same way that native compilers align types. Fundamental types have natural alignments that are usually the rounded-up integral power of two closest to their size:

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

When assembling a type, the compiler will make sure that all fields of any given type have their starting offset within the instance aligned to a boundary that matches that type - assuming that explicit layout isn't being used.

User-defined types themselves have an alignment, which is calculated as the highest alignment of any of their field types. The type's size is extended if necessary to make the size of the type aligned too.

But of course, all reference types are still only IntPtr.Size in size and alignment, so the size of reference type will not affect arrays of that type.

Note that the CLR may choose, at its discretion, to layout types differently than described above, maybe to increase cache locality or reduce padding required by alignment.

生来就爱笑 2024-07-16 15:55:03

据估计(2017 年),您可以调试应用程序,在字典生效之前设置断点,拍摄“内存使用情况快照”(选项卡:诊断工具<下的内存使用情况) /em>),填写你的字典并获取另一个快照。

这并不准确,但它是一个很好的猜测。

As an estimate (in 2017) you can debug into your application, set a breakpoint before your dictionary comes to life, take a "Memory Usage Snapshot" (Tab: Memory Usage under Diagnostic Tools), fill your dictionary and get another snapshot.

It is not exact, but it is a good guesstimate.

晨敛清荷 2024-07-16 15:55:03

在像 Dictionary 这样的情况下,您可以通过二进制序列化来获取对象大小。 这是示例代码:

var dictionary = new DictionaryGenerator().GetSomeLargeDictionary();
var memoryStream = new System.IO.MemoryStream();
var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(memoryStream, dictionary);
Console.WriteLine($"Size of dictionary: {memoryStream.Position} byte(s)");

In cases like Dictionary<TKey, TValue>, you can hack getting the object size by binary serialization. Here is a sample code:

var dictionary = new DictionaryGenerator().GetSomeLargeDictionary();
var memoryStream = new System.IO.MemoryStream();
var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(memoryStream, dictionary);
Console.WriteLine(
quot;Size of dictionary: {memoryStream.Position} byte(s)");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文