C#/ .NET对象使用多少内存?

时间:2022-09-14 03:32:14

I'm developing an application which currently have hundreds of objects created.

我正在开发一个目前有数百个对象创建的应用程序。

Is it possible to determine (or approximate) the memory allocated by an object (class instance)?

是否可以确定(或近似)对象(类实例)分配的内存?

9 个解决方案

#1


38  

You could use a memory profiler like

您可以使用类似的内存分析器

.NET Memory Profiler (http://memprofiler.com/)

.NET Memory Profiler(http://memprofiler.com/)

or

要么

CLR Profiler (free) (http://clrprofiler.codeplex.com/)

CLR Profiler(免费)(http://clrprofiler.codeplex.com/)

#2


36  

A coarse way could be this in-case you wanna know whats happening with a particular object

粗略的方式可能是这种情况,你想知道特定对象发生的事情

// Measure starting point memory use
GC_MemoryStart = System.GC.GetTotalMemory(true);

// Allocate a new byte array of 20000 elements (about 20000 bytes)
MyByteArray = new byte[20000];

// Obtain measurements after creating the new byte[]
GC_MemoryEnd = System.GC.GetTotalMemory(true);

// Ensure that the Array stays in memory and doesn't get optimized away
GC.KeepAlive(MyByteArray);

process wide stuff could be obtained perhaps like this

可能会像这样获得流程广泛的东西

long Process_MemoryStart = 0;
Process MyProcess = System.Diagnostics.Process.GetCurrentProcess();
Process_MemoryStart = MyProcess.PrivateMemorySize64;

hope this helps ;)

希望这可以帮助 ;)

#3


10  

The ANTS memory profiler will tell you exactly how much is allocated for each object/method/etc.

ANTS内存分析器将告诉您为每个对象/方法/等分配了多少。

#4


9  

Here's a related post where we discussed determining the size of reference types.

这是一篇相关文章,我们讨论了确定参考类型的大小。

#5


6  

You can also use WinDbg and either SOS or SOSEX (like SOS with with a lot more commands and some existing ones improved) WinDbg extensions. The command you would use to analyze an object at a particular memory address is !objsize

你也可以使用WinDbg和SOS或SOSEX(比如SOS带有更多命令和一些现有的改进)WinDbg扩展。用于分析特定内存地址对象的命令是!objsize

One VERY important item to remember is that !objsize only gives you the size of the class itself and DOES NOT necessarily include the size of the aggregate objects contained inside the class - I have no idea why it doesn't do this as it is quite frustrating and misleading at times.

要记住的一个非常重要的项目是!objsize只给出了类本身的大小,并且不一定包括类中包含的聚合对象的大小 - 我不知道它为什么不这样做因为它是相当的有时令人沮丧和误导。

I've created 2 Feature Suggestions on the Connect website that ask for this ability to be included in VisualStudio. Please vote for the items of you would like to see them added as well!

我在Connect网站上创建了2个功能建议,要求将此功能包含在VisualStudio中。请投票支持您希望添加的项目!

https://connect.microsoft.com/VisualStudio/feedback/details/637373/add-feature-to-debugger-to-view-an-objects-memory-footprint-usage

https://connect.microsoft.com/VisualStudio/feedback/details/637373/add-feature-to-debugger-to-view-an-objects-memory-footprint-usage

https://connect.microsoft.com/VisualStudio/feedback/details/637376/add-feature-to-debugger-to-view-an-objects-rooted-references

https://connect.microsoft.com/VisualStudio/feedback/details/637376/add-feature-to-debugger-to-view-an-objects-rooted-references

EDIT: I'm adding the following to clarify some info from the answer provided by Charles Bretana:

编辑:我正在添加以下内容以澄清Charles Bretana提供的答案中的一些信息:

  1. the OP asked about the size of an 'object' not a 'class'. An object is an instance of a class. Maybe this is what you meant?
  2. OP询问“对象”的大小而不是“类”。对象是类的实例。也许这就是你的意思?
  3. The memory allocated for an object does not include the JITted code. The JIT code lives in its own 'JIT Code Heap'.
  4. 为对象分配的内存不包括JITted代码。 JIT代码存在于自己的“JIT代码堆”中。
  5. The JIT only compiles code on a method by method basis - not at a class level. So if a method never gets called for a class, it is never JIT compiled and thus never has memory allocated for it on the JIT Code Heap.
  6. JIT仅在逐个方法的基础上编译代码 - 而不是在类级别。因此,如果一个方法永远不会被调用一个类,它永远不会被JIT编译,因此永远不会在JIT代码堆上为它分配内存。

As an aside, there are about 8 different heaps that the CLR uses:

另外,CLR使用了大约8种不同的堆:

  1. Loader Heap: contains CLR structures and the type system
  2. Loader Heap:包含CLR结构和类型系统
  3. High Frequency Heap: statics, MethodTables, FieldDescs, interface map
  4. 高频堆:静态,MethodTables,FieldDescs,接口映射
  5. Low Frequency Heap: EEClass, ClassLoader and lookup tables
  6. 低频堆:EEClass,ClassLoader和查找表
  7. Stub Heap: stubs for CAS, COM wrappers, P/Invoke
  8. Stub Heap:CAS,COM包装器,P / Invoke的存根
  9. Large Object Heap: memory allocations that require more than 85k bytes
  10. 大对象堆:需要超过85k字节的内存分配
  11. GC Heap: user allocated heap memory private to the app
  12. GC堆:用户分配的堆内存专用于应用程序
  13. JIT Code Heap: memory allocated by mscoreee (Execution Engine) and the JIT compiler for managed code
  14. JIT代码堆:由mscoreee(执行引擎)分配的内存和托管代码的JIT编译器
  15. Process/Base Heap: interop/unmanaged allocations, native memory, etc
  16. 进程/基本堆:互操作/非托管分配,本机内存等

HTH

HTH

#6


5  

To get a general sense for the memory allocation in your application, use the following sos command in WinDbg

要了解应用程序中内存分配的一般意义,请在WinDbg中使用以下sos命令

!dumpheap -stat

Note that !dumpheap only gives you the bytes of the object type itself, and doesn't include the bytes of any other object types that it might reference.

请注意,!dumpheap仅为您提供对象类型本身的字节,并且不包括它可能引用的任何其他对象类型的字节。

If you want to see the total held bytes (sum all the bytes of all objects referenced by your object) of a specific object type, use a memory profiler like dot Trace - http://www.jetbrains.com/profiler/

如果要查看特定对象类型的总保持字节数(对象引用的所有对象的所有字节数),请使用内存分析器,如dot Trace - http://www.jetbrains.com/profiler/

#7


5  

Each "class" requires enough memory to hold all of it's jit-compiled code for all it's members that have been called by the runtime, (although if you don;t call a method for quite some time, the CLR can release that memory and re-jit it again if you call it again... plus enough memory to hold all static variables declared in the class... but this memory is allocated only once per class, no matter how many instances of the class you create.

每个“类”都需要足够的内存来保存所有它的运行时调用的所有成员的jit编译代码(尽管如果你不调用方法很长一段时间,CLR可以释放那个内存和如果你再次调用它再次重新启动...加上足够的内存来保存类中声明的所有静态变量...但是这个内存每个类只分配一次,无论你创建的类的实例数是多少。

For each instance of the class that you create, (and has not been Garbage collected) you can approximate the memory footprint by adding up the memory usage by each instance-based declared variable... (field)

对于您创建的类的每个实例(并且尚未收集垃圾),您可以通过将每个基于实例的声明变量的内存使用量相加来估算内存占用量...(字段)

reference variables (refs to other objects) take 4 or 8 bytes (32/64 bit OS ?) int16, Int32, Int64 take 2,4, or 8 bytes, respectively...

引用变量(引用其他对象)需要4或8个字节(32/64位OS?)int16,Int32,Int64分别取2,4或8个字节...

string variable takes extra storage for some meta data elements, (plus the size of the address pointer)

字符串变量为某些元数据元素占用额外的存储空间(加上地址指针的大小)

In addition, each reference variable in an object could also be considered to "indirectly" include the memory taken up on the heap by the object it points to, although you would probably want to count that memory as belonging to that object not the variable that references it...

此外,对象中的每个引用变量也可以被认为是“间接地”包括它指向的对象在堆上占用的内存,尽管您可能希望将该内存计为属于该对象而不是变量引用它......

etc. etc.

等等

#8


4  

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

#9


0  

There is the academic question of What is the size of an object at runtime? And that is interesting, but it can only be properly answered by a profiler that is attached to the running process. I spent quite a while looking at this recently and determined that there is no generic method that is accurate and fast enough that you would ever want to use it in a production system. Simple cases like arrays of numerical types have easy answers, but beyond this the best answer would be Don't bother trying to work it out. Why do you want to know this? Is there other information available that could serve the same purpose?

有一个学术问题:运行时对象的大小是多少?这很有趣,但它只能通过附加到正在运行的进程的探查器来正确回答。我最近花了很长时间看这个,并确定没有足够准确和快速的通用方法,你可能希望在生产系统中使用它。像数组类型的数组这样的简单案例有简单的答案,但除此之外,最好的答案是不要试图解决它。你为什么想知道这个?是否有其他可用于同一目的的信息?

In my case I ended up wanting to answer this question because I had various data that were useful, but could be discarded to free up RAM for more critical services. The poster boys here are an Undo Stack and a Cache.

在我的情况下,我最终想要回答这个问题,因为我有各种有用的数据,但可以放弃以释放RAM以获得更多关键服务。这里的海报男孩是Undo Stack和Cache。

Eventually I concluded that the right way to manage the size of the undo stack and the cache was to query for the amount of available memory (it's a 64-bit process so it is safe to assume it is all available) and then allow more items to be added if there is a sufficiently large buffer of RAM and require items to be removed if RAM is running low.

最后我得出结论,管理撤销堆栈和缓存大小的正确方法是查询可用内存量(这是一个64位进程,因此可以安全地假设它全部可用)然后允许更多项目如果存在足够大的RAM缓冲区并且在RAM运行不足时需要删除项目,则添加。

#1


38  

You could use a memory profiler like

您可以使用类似的内存分析器

.NET Memory Profiler (http://memprofiler.com/)

.NET Memory Profiler(http://memprofiler.com/)

or

要么

CLR Profiler (free) (http://clrprofiler.codeplex.com/)

CLR Profiler(免费)(http://clrprofiler.codeplex.com/)

#2


36  

A coarse way could be this in-case you wanna know whats happening with a particular object

粗略的方式可能是这种情况,你想知道特定对象发生的事情

// Measure starting point memory use
GC_MemoryStart = System.GC.GetTotalMemory(true);

// Allocate a new byte array of 20000 elements (about 20000 bytes)
MyByteArray = new byte[20000];

// Obtain measurements after creating the new byte[]
GC_MemoryEnd = System.GC.GetTotalMemory(true);

// Ensure that the Array stays in memory and doesn't get optimized away
GC.KeepAlive(MyByteArray);

process wide stuff could be obtained perhaps like this

可能会像这样获得流程广泛的东西

long Process_MemoryStart = 0;
Process MyProcess = System.Diagnostics.Process.GetCurrentProcess();
Process_MemoryStart = MyProcess.PrivateMemorySize64;

hope this helps ;)

希望这可以帮助 ;)

#3


10  

The ANTS memory profiler will tell you exactly how much is allocated for each object/method/etc.

ANTS内存分析器将告诉您为每个对象/方法/等分配了多少。

#4


9  

Here's a related post where we discussed determining the size of reference types.

这是一篇相关文章,我们讨论了确定参考类型的大小。

#5


6  

You can also use WinDbg and either SOS or SOSEX (like SOS with with a lot more commands and some existing ones improved) WinDbg extensions. The command you would use to analyze an object at a particular memory address is !objsize

你也可以使用WinDbg和SOS或SOSEX(比如SOS带有更多命令和一些现有的改进)WinDbg扩展。用于分析特定内存地址对象的命令是!objsize

One VERY important item to remember is that !objsize only gives you the size of the class itself and DOES NOT necessarily include the size of the aggregate objects contained inside the class - I have no idea why it doesn't do this as it is quite frustrating and misleading at times.

要记住的一个非常重要的项目是!objsize只给出了类本身的大小,并且不一定包括类中包含的聚合对象的大小 - 我不知道它为什么不这样做因为它是相当的有时令人沮丧和误导。

I've created 2 Feature Suggestions on the Connect website that ask for this ability to be included in VisualStudio. Please vote for the items of you would like to see them added as well!

我在Connect网站上创建了2个功能建议,要求将此功能包含在VisualStudio中。请投票支持您希望添加的项目!

https://connect.microsoft.com/VisualStudio/feedback/details/637373/add-feature-to-debugger-to-view-an-objects-memory-footprint-usage

https://connect.microsoft.com/VisualStudio/feedback/details/637373/add-feature-to-debugger-to-view-an-objects-memory-footprint-usage

https://connect.microsoft.com/VisualStudio/feedback/details/637376/add-feature-to-debugger-to-view-an-objects-rooted-references

https://connect.microsoft.com/VisualStudio/feedback/details/637376/add-feature-to-debugger-to-view-an-objects-rooted-references

EDIT: I'm adding the following to clarify some info from the answer provided by Charles Bretana:

编辑:我正在添加以下内容以澄清Charles Bretana提供的答案中的一些信息:

  1. the OP asked about the size of an 'object' not a 'class'. An object is an instance of a class. Maybe this is what you meant?
  2. OP询问“对象”的大小而不是“类”。对象是类的实例。也许这就是你的意思?
  3. The memory allocated for an object does not include the JITted code. The JIT code lives in its own 'JIT Code Heap'.
  4. 为对象分配的内存不包括JITted代码。 JIT代码存在于自己的“JIT代码堆”中。
  5. The JIT only compiles code on a method by method basis - not at a class level. So if a method never gets called for a class, it is never JIT compiled and thus never has memory allocated for it on the JIT Code Heap.
  6. JIT仅在逐个方法的基础上编译代码 - 而不是在类级别。因此,如果一个方法永远不会被调用一个类,它永远不会被JIT编译,因此永远不会在JIT代码堆上为它分配内存。

As an aside, there are about 8 different heaps that the CLR uses:

另外,CLR使用了大约8种不同的堆:

  1. Loader Heap: contains CLR structures and the type system
  2. Loader Heap:包含CLR结构和类型系统
  3. High Frequency Heap: statics, MethodTables, FieldDescs, interface map
  4. 高频堆:静态,MethodTables,FieldDescs,接口映射
  5. Low Frequency Heap: EEClass, ClassLoader and lookup tables
  6. 低频堆:EEClass,ClassLoader和查找表
  7. Stub Heap: stubs for CAS, COM wrappers, P/Invoke
  8. Stub Heap:CAS,COM包装器,P / Invoke的存根
  9. Large Object Heap: memory allocations that require more than 85k bytes
  10. 大对象堆:需要超过85k字节的内存分配
  11. GC Heap: user allocated heap memory private to the app
  12. GC堆:用户分配的堆内存专用于应用程序
  13. JIT Code Heap: memory allocated by mscoreee (Execution Engine) and the JIT compiler for managed code
  14. JIT代码堆:由mscoreee(执行引擎)分配的内存和托管代码的JIT编译器
  15. Process/Base Heap: interop/unmanaged allocations, native memory, etc
  16. 进程/基本堆:互操作/非托管分配,本机内存等

HTH

HTH

#6


5  

To get a general sense for the memory allocation in your application, use the following sos command in WinDbg

要了解应用程序中内存分配的一般意义,请在WinDbg中使用以下sos命令

!dumpheap -stat

Note that !dumpheap only gives you the bytes of the object type itself, and doesn't include the bytes of any other object types that it might reference.

请注意,!dumpheap仅为您提供对象类型本身的字节,并且不包括它可能引用的任何其他对象类型的字节。

If you want to see the total held bytes (sum all the bytes of all objects referenced by your object) of a specific object type, use a memory profiler like dot Trace - http://www.jetbrains.com/profiler/

如果要查看特定对象类型的总保持字节数(对象引用的所有对象的所有字节数),请使用内存分析器,如dot Trace - http://www.jetbrains.com/profiler/

#7


5  

Each "class" requires enough memory to hold all of it's jit-compiled code for all it's members that have been called by the runtime, (although if you don;t call a method for quite some time, the CLR can release that memory and re-jit it again if you call it again... plus enough memory to hold all static variables declared in the class... but this memory is allocated only once per class, no matter how many instances of the class you create.

每个“类”都需要足够的内存来保存所有它的运行时调用的所有成员的jit编译代码(尽管如果你不调用方法很长一段时间,CLR可以释放那个内存和如果你再次调用它再次重新启动...加上足够的内存来保存类中声明的所有静态变量...但是这个内存每个类只分配一次,无论你创建的类的实例数是多少。

For each instance of the class that you create, (and has not been Garbage collected) you can approximate the memory footprint by adding up the memory usage by each instance-based declared variable... (field)

对于您创建的类的每个实例(并且尚未收集垃圾),您可以通过将每个基于实例的声明变量的内存使用量相加来估算内存占用量...(字段)

reference variables (refs to other objects) take 4 or 8 bytes (32/64 bit OS ?) int16, Int32, Int64 take 2,4, or 8 bytes, respectively...

引用变量(引用其他对象)需要4或8个字节(32/64位OS?)int16,Int32,Int64分别取2,4或8个字节...

string variable takes extra storage for some meta data elements, (plus the size of the address pointer)

字符串变量为某些元数据元素占用额外的存储空间(加上地址指针的大小)

In addition, each reference variable in an object could also be considered to "indirectly" include the memory taken up on the heap by the object it points to, although you would probably want to count that memory as belonging to that object not the variable that references it...

此外,对象中的每个引用变量也可以被认为是“间接地”包括它指向的对象在堆上占用的内存,尽管您可能希望将该内存计为属于该对象而不是变量引用它......

etc. etc.

等等

#8


4  

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

#9


0  

There is the academic question of What is the size of an object at runtime? And that is interesting, but it can only be properly answered by a profiler that is attached to the running process. I spent quite a while looking at this recently and determined that there is no generic method that is accurate and fast enough that you would ever want to use it in a production system. Simple cases like arrays of numerical types have easy answers, but beyond this the best answer would be Don't bother trying to work it out. Why do you want to know this? Is there other information available that could serve the same purpose?

有一个学术问题:运行时对象的大小是多少?这很有趣,但它只能通过附加到正在运行的进程的探查器来正确回答。我最近花了很长时间看这个,并确定没有足够准确和快速的通用方法,你可能希望在生产系统中使用它。像数组类型的数组这样的简单案例有简单的答案,但除此之外,最好的答案是不要试图解决它。你为什么想知道这个?是否有其他可用于同一目的的信息?

In my case I ended up wanting to answer this question because I had various data that were useful, but could be discarded to free up RAM for more critical services. The poster boys here are an Undo Stack and a Cache.

在我的情况下,我最终想要回答这个问题,因为我有各种有用的数据,但可以放弃以释放RAM以获得更多关键服务。这里的海报男孩是Undo Stack和Cache。

Eventually I concluded that the right way to manage the size of the undo stack and the cache was to query for the amount of available memory (it's a 64-bit process so it is safe to assume it is all available) and then allow more items to be added if there is a sufficiently large buffer of RAM and require items to be removed if RAM is running low.

最后我得出结论,管理撤销堆栈和缓存大小的正确方法是查询可用内存量(这是一个64位进程,因此可以安全地假设它全部可用)然后允许更多项目如果存在足够大的RAM缓冲区并且在RAM运行不足时需要删除项目,则添加。