Try increasing the detail to see if it's including the size of the actual objects referenced.
In comparison, try the following program:
class MemTest
{
private static object[] TakeUpSpace = new object[1024 * 1024];
public static void Main(string[] args)
{
var arr = TakeUpSpace;//make sure it's instantiated.
Console.ReadKey(true);//keep running so we can profile.
}
}
Profiling this on a 32 bit machine shows a 4MB sized array - 4 * 1024 * 1024, but no actual objects referred to.
However this:
class MemTest
{
private static object[] TakeUpSpace = new object[1024];
public static void Main(string[] args)
{
var arr = TakeUpSpace;//make sure it's instantiated.
for(var i = 0; i != 1024; ++i)
arr[i] = new object();
Console.ReadKey(true);//keep running so we can profile.
}
}
Shows the array to be 16KB. The object[]
itself is 1024 * 4 = 4KB, but each object is at least 3 * pointer-size large (size of fields with a minimum of one pointer-size, plus a header of two pointer-sizes per object).
Requested explanation of header.
Every .NET object obviously contains the fields defined for it. If there are no fields, or the fields are less than the size of a reference, it'll take up that much anyway as a minimum.
Every .NET object contains a syncblock that contains information on whether a lock is held on it, and some other information used for marshalling.
Every .NET object contains a type-handle, from which we can find out which type it is, the implementation of a virtual member, and other type-related information.
As such, when you have an actual object - rather than a null reference, you are guaranteed to be taking up at least 12bytes of memory for the object, along with 4 for the reference to it (there can of course be more than one reference to the same object). You could though be taking up more if the object has more fields or larger fields, and very often will be.