2

What is the easiest way to find out how much memory an object uses in .NET?

Preferably without having to resort to a third party tool. Marshal.SizeOf or the sizeof operator look useful but only work with a restricted range of types.

Some related posts:

Community
  • 1
  • 1
Thomas Bratt
  • 48,038
  • 36
  • 121
  • 139

3 Answers3

2

Asked and answered here: Determine how much memory a class uses?

The quick summary is that if you don't want to use a tool, you need to use the .NET Profiling API

The Profiling API is amazingly powerful, but I don't think it would qualify as "easy" by any stretch of the imagination, so I would strongly recommend using a memory profiling tool - there are some free ones that are OK, and some not-too-expensive commercial ones (JetBrains dotTrace in particular) that are really good.

Community
  • 1
  • 1
McKenzieG1
  • 13,960
  • 7
  • 36
  • 42
0

Because of .NET's garbage-collected nature, it's somewhat difficult to measure how much memory is really being used. If you want to measure the size of a class instance, for example, does it include the memory used by instances that your instance points to?

If the answer is no, add up the size of all of the fields: Using reflection, iterate through all members of the class; use Marshal.Sizeof(member.Type) for anything that typeof(ValueType).IsAssignableFrom(member.Type) - this measures primitive types and structs, all of which reside in the class's instance allocation. Every reference type (anything that isn't assignable to a valuetype) will take IntPtr.Size. There are a disgusting number of exceptions to this, but it might work for you.

If the answer is yes, you have a serious problem. Multiple things can reference a single instance, so if 'a' and 'b' both point to 'c', then RecursiveSizeOf(a) + RecursiveSizeOf(b) would be larger than SimpleSizeOf(a) + SimpleSizeOf(b) + SimpleSizeOf(c).

Even worse, measuring recursively can lead you down circular references, or lead you to objects you don't intend to measure - if a class is referencing a mutex, for example, that mutex may point to the thread that owns it. That thread may point to all of its local variables, which point to some C# framework structures... you may end up measuring your entire program.

It might help to understand that a garbage-collected language like C# is somewhat "fuzzy" (from a completely non-technical sense) in the way it draws distinctions between objects and units of memory. This is a lot of what Marshal mitigates - marshaling rules ensure that the struct you're marshaling (or measuring) has a well-defined memory layout, and therefore a well-defined size. In which case, you should be using well-defined, marshalable structs if you intend on using Marhsal.SizeOf().

Another option is serialization. This won't tell you specifically how much memory is in use, but it will give you a relative idea of the size of the object. But again, in order to serialize things, they have to have a well-defined layout (and therefore a well-defined size) - you accomplish by making the class appropriately serializable.

I can post implementation examples if any of the above options appeal to you.

Kenzi
  • 1,059
  • 8
  • 10
0

you could also do something like this:

int startMem = GC.GetTotalMemory(true);
YourClass c = new YourClass();
int endMem = GC.GetTotalMemory(true);
int usedMeme = endMem - startMem;
Mladen
  • 1,710
  • 12
  • 4
  • I doubt that that is going to work, in the general case. Allocating an object can trigger a new garbage collection cycle, for one thing. Even though you're calling GetTotalMemory(true), someting could be happening in a different thread that effects the result. – Mark Bessey Sep 30 '08 at 21:00
  • That is incredibly brittle; in any non-trivial setup you can't guarantee that nothing else is happening. Threading etc... – Marc Gravell Sep 30 '08 at 21:01
  • 1
    I don't know...Combine this with checking GC.CollectionCount before and after, and you can at least know if your number is inaccurate. Certainly meets the easy test better than the Profiler API, and will probably work in the 80% case. +1 from me. – Mark Brackett Oct 22 '08 at 21:00
  • It looks like this is not possible but Mladen's answer is the closest for all its flaws 8) – Thomas Bratt Dec 08 '09 at 23:07