How much memory does a C#/.NET object use?

C#.NetObjectMemoryProfiling

C# Problem Overview


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)?

C# Solutions


Solution 1 - C#

You could use a memory profiler like

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

or

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

Solution 2 - C#

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 ;)

Solution 3 - C#

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

Solution 4 - C#

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

Solution 5 - C#

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

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.

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!

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

EDIT: I'm adding the following to clarify some info from the answer provided by 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. The memory allocated for an object does not include the JITted code. The JIT code lives in its own 'JIT Code Heap'.
  3. 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.

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

  1. Loader Heap: contains CLR structures and the type system
  2. High Frequency Heap: statics, MethodTables, FieldDescs, interface map
  3. Low Frequency Heap: EEClass, ClassLoader and lookup tables
  4. Stub Heap: stubs for CAS, COM wrappers, P/Invoke
  5. Large Object Heap: memory allocations that require more than 85k bytes
  6. GC Heap: user allocated heap memory private to the app
  7. JIT Code Heap: memory allocated by mscoreee (Execution Engine) and the JIT compiler for managed code
  8. Process/Base Heap: interop/unmanaged allocations, native memory, etc

HTH

Solution 6 - C#

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.

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...

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.

Solution 7 - C#

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

!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.

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/

Solution 8 - C#

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

Solution 9 - C#

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.

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.

Solution 10 - C#

For any Unity Dev lurking around for an answer, here's a way to compare two different class memory allocations inspired by @varun's answer:

void Start()
    {
        var totalMemory = System.GC.GetTotalMemory(false);
        
        var class1 = new Class1[100000];
        System.GC.KeepAlive(class1);
        for (int i = 0; i < 100000; i++)
        {
            class1[i] = new Class1();
        }

        var newTotalMemory = System.GC.GetTotalMemory(false);
        Debug.Log($"Class1: {newTotalMemory} - {totalMemory} = {newTotalMemory - totalMemory}");

        var class2 = new Class2[100000];
        System.GC.KeepAlive(class2);
        for (int i = 0; i < 100000; i++)
        {
            class2[i] = new Class2(10, 10);
        }

        var newTotalMemory2 = System.GC.GetTotalMemory(false);
        Debug.Log($"Class2: {newTotalMemory2} - {newTotalMemory} = {newTotalMemory2 - newTotalMemory}");
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFerranBView Question on Stackoverflow
Solution 1 - C#RauhotzView Answer on Stackoverflow
Solution 2 - C#varunView Answer on Stackoverflow
Solution 3 - C#George StockerView Answer on Stackoverflow
Solution 4 - C#John SheehanView Answer on Stackoverflow
Solution 5 - C#Dave BlackView Answer on Stackoverflow
Solution 6 - C#Charles BretanaView Answer on Stackoverflow
Solution 7 - C#SeanView Answer on Stackoverflow
Solution 8 - C#serhioView Answer on Stackoverflow
Solution 9 - C#satnhakView Answer on Stackoverflow
Solution 10 - C#ExplosionView Answer on Stackoverflow