18

Are there ways at determining the total size of a complex object in .NET? This object is composed of other objects and might hold references to other complex objects. Some of the objects encapsulated by this object might be POD, others may not.

DigitalZebra
  • 39,494
  • 39
  • 114
  • 146
  • 1
    Are the objects serializable? –  Jun 16 '10 at 21:12
  • they MIGHT be :) Sorry for being vague, but I'm trying to make this question as generic as possible. – DigitalZebra Jun 16 '10 at 21:13
  • What is "POD" in C#/.NET context? It's a C++ term... – Pavel Minaev Jun 16 '10 at 21:18
  • @Pavel, yes, POD is a C++ term... I'm using POD to refer to int, string, float, double etc... basically the POD types for .NET... value types :) – DigitalZebra Jun 16 '10 at 21:22
  • I believe the most appropriate CLR term for what you mean is "blittable type" - which is all primitive types (this excludes object references) and structs where all fields are themselves blittable types. – Pavel Minaev Jun 16 '10 at 21:26
  • Wouldn't the C# version of POD be called simple types? By the way, if anyone is like me and have never heard of POD, it stands for *Plain Ol' Data*. – Chad Levy Jun 16 '10 at 21:27

5 Answers5

10

What you have is not a "complex object", it's an object graph. To determine its total size, you need to walk that graph - starting with some root object, and using Reflection to enumerate fields of reference types and retrieving their values (and checking for loops, of course).

To get the size of a particular object in the graph, see this answer to a related question, but note that this is an evil hack, completely unsupported, may break (and may already be broken), and may result in a wholesale kitten genocide in heavenly spheres. That said, there is no "non-hacky" way to get a precise value, because it is an implementation detail by definition - you shouldn't have any use for it. And for the purpose of finding out the memory usage of an app during debugging/profiling, the hack is good enough.

Community
  • 1
  • 1
Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
  • Thanks Pavel. I understood the complexities when I asked the question, I was just curious as to if someone had already created an object graph traversal which calculated this :) – DigitalZebra Jun 16 '10 at 21:50
4

Put simply, there is no way to know. Assuming all the objects are serializable, you could use a BinaryFormatter to serialize them into a binary blob, and then read the size of that. However, this would include some metadata, and inflate the actual object size (but it would be a reasonable estimate).

For value types, you would use Marshal.SizeOf(), only it does not take into account any subobjects. It would calculate any internal reference type as the size of the pointer to it.

Reflection is another way, but would not expose any private members taking up memory. So, unless I'm mistaken, there is no way to really do this properly.

drharris
  • 11,194
  • 5
  • 43
  • 56
2

Tricky...

What if two objects point to the same string variable. Which one "owns" the string? It sounds to me you need to simulate a garbage collection to get a true answer. Not exactly light weight.

  • 2
    @Paul: what does immutability have to do with this? The point is that an object may hold a reference to a string that has been given to it from the outside (e.g. a filename). Does that string "belong" to the object or not? Should it be counted as part of its size or not? – Pavel Minaev Jun 16 '10 at 21:38
1

Give System.Runtime.InteropServices.Marshal.SizeOf() a shot.

Matt Greer
  • 60,826
  • 17
  • 123
  • 123
1

Previously answered elsewhere on StackOverflow:

Find size of object instance in bytes in c#

You need to introduce unsafe code (due to pointer operations required for this) - the code looks like this:

static unsafe int CalcSize(object obj)
{
    RuntimeTypeHandle th = obj.GetType().TypeHandle;
    int size = *(*(int**)&th + 1);
    return size;
}

Also remember to mark the project settings (Project->Build tab) to "Allow unsafe code".

code4life
  • 15,655
  • 7
  • 50
  • 82