Is there a way to programmatically and accurately determine the amount of memory used by an object in c#? I am not concerned with how slow the process is, so running GCs left and right is acceptable (of course I'd prefer something more efficient).
Serializing objects and looking at the resulting length doesn't seem very accurate (in a simple test of this method, I saw that an integer returned a value of 54).
Using GC.GetTotalMemory(true)
seems to produce inconsistent values, not to mention they appear too large.
Using Marshal.SizeOf(object)
produces accurate results, but only appears to work with primitives.
If nothing along those lines is available, an alternative would be to calculate sizes based on the structures used and the primitives involved. This would also be acceptable (though upsetting), but I'd need to know the correct method of calculating object overheads, etc. Any literature that would show me a way to do this would be awesome.
Similar SO questions (none of which seemed to have concrete methods for accurate calculation of object size):
How much memory does a C#/.NET object use?
How to get memory available or used in C#
How to get object size in memory?
sizeof() equivalent for reference types?
Tools to profile memory (non-programmatic approach):
http://www.microsoft.com/en-us/download/details.aspx?id=16273
Find out how much memory is being used by an object in C#?
another idea is to have a helper class to do this by reflecting the object and extract its all data members and gather all fields size by sizeof() , it will be a little bit complicated but it is implementable
this class will calculate the actual size of an object , but i have tested it just a few times and a few objects were tested but i think i will be working.
public class SizeHelper
{
private static int GetTypeSizeArray(string typeName, object objValue)
{
switch (typeName)
{
case "System.Double[]":
return sizeof(System.Double) * ((System.Double[]) objValue).Length ;
case "System.Single[]":
return sizeof(System.Single) * ((System.Single[])objValue).Length;
case "System.Char[]":
return sizeof(System.Char) * ((System.Char[])objValue).Length;
case "System.Int16[]":
return sizeof(System.Int16) * ((System.Int16[])objValue).Length;
case "System.Int32[]":
return sizeof(System.Int32) * ((System.Int32[])objValue).Length;
case "System.Int64[]":
return sizeof(System.Int64) * ((System.Int64[])objValue).Length;
case "System.UInt16[]":
return sizeof(System.UInt16) * ((System.UInt16[])objValue).Length;
case "System.UInt32[]":
return sizeof(System.UInt32) * ((System.UInt32[])objValue).Length;
case "System.UInt64[]":
return sizeof(System.UInt64) * ((System.UInt64[])objValue).Length;
case "System.Decimal[]":
return sizeof(System.Decimal) * ((System.Decimal[])objValue).Length;
case "System.Byte[]":
return sizeof(System.Byte) * ((System.Byte[])objValue).Length;
case "System.SByte[]":
return sizeof(System.SByte) * ((System.SByte[])objValue).Length;
case "System.Boolean":
return sizeof (System.Boolean)*((System.Boolean[]) objValue).Length;
default:
return 0;
}
}
public static int GetSize(object obj)
{
Type t = obj.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
int size = 0;
foreach (FieldInfo fieldInfo in fields)
{
if (fieldInfo.FieldType.BaseType.FullName.Equals("System.ValueType"))
{
size += GetTypeSize(fieldInfo.FieldType.FullName);
}
else if (fieldInfo.FieldType.BaseType.FullName.Equals("System.Array"))
{
var subObj = fieldInfo.GetValue(obj);
if (subObj != null)
size += GetTypeSizeArray(fieldInfo.FieldType.FullName, subObj);
}
else if(fieldInfo.FieldType.FullName.Equals("System.String"))
{
var subObj = fieldInfo.GetValue(obj);
if (subObj != null)
{
size += subObj.ToString().Length*sizeof (System.Char);
}
}
else
{
var subObj = fieldInfo.GetValue(obj);
if (subObj != null)
size += GetSize(subObj);
}
}
return size;
}
private static int GetTypeSize(string typeName)
{
switch (typeName)
{
case "System.Double":
return sizeof(System.Double);
case "System.Single":
return sizeof(System.Single);
case "System.Char":
return sizeof(System.Char);
case "System.Int16":
return sizeof(System.Int16);
case "System.Int32":
return sizeof(System.Int32);
case "System.Int64":
return sizeof(System.Int64);
case "System.UInt16":
return sizeof(System.UInt16);
case "System.UInt32":
return sizeof(System.UInt32);
case "System.UInt64":
return sizeof(System.UInt64);
case "System.Decimal":
return sizeof(System.Decimal);
case "System.Byte":
return sizeof(System.Byte);
case "System.SByte":
return sizeof(System.SByte);
case "System.Boolean":
return sizeof (System.Boolean);
default:
return 0;
}
}
}
object obj = new List<int>(); // whatever you want to get the size of
RuntimeTypeHandle th = obj.GetType().TypeHandle;
int size = *(*(int**)&th + 1);
Console.WriteLine(size);
I dont know whether it is useful to you or not...but try to refer this link...espacialy fig.4
http://msdn.microsoft.com/en-us/magazine/cc163791.aspx#S9