如何在内存中找到对象的大小?

时间:2013-08-17 16:20:16

标签: c#

我知道这篇文章可能看似重复,但我阅读了所有这些文章并开发了一个测试主题的样本

Find size of object instance in bytes in c# http://www.codeproject.com/Questions/177604/Size-of-a-class-in-c How to get object size in memory? Getting the size of a field in bytes with C# http://blogs.msdn.com/b/cbrumme/archive/2003/04/15/51326.aspx

我有一个类whiteout任何属性或字段,它只是为了测试它的大小是空的。

[Serializable]
public class MemberStateModel
{


}

我创建一个对象并通过以下代码获取它的大小:

 static void Main(string[] args)
    {
        MemberStateModel o = new MemberStateModel() {};
        long size;

        using (Stream s = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(s, o);
            size = s.Length;
        }
    }

现在它的大小显示数字159,通过那些帖子我认为这意味着我的o大小是159kbyte但是 我认为它不正确的方式和空物体不能有这个尺寸,是真的吗?

这对我来说非常重要,因为我将一些用户的数据存储在会话中,如果这个大小在我的网站中添加用户增长,我将需要更多的物理内存来处理我的Web应用程序

3 个答案:

答案 0 :(得分:1)

BinaryFormatter告诉您将类序列化为二进制所需的字节数。这与类在内存中占用的大小非常不同。例如,BinaryFormatter将有关类型的信息写入流中。

对象在内存中使用的大小不是在编译时定义的,而是在运行时定义的,因为JIT编译器决定最终的布局。现在问题是如何找出尺寸。虽然我有一个结构的解决方案(创建一个数组,做指针算术),我不知道如何找到类的。一种解决方案是将您的类MemberStateModel定义为结构,测量它,然后转回一个类,假设它将具有相同的大小。

您还可以通过将字段的大小计算为下限来估计大小(因为填充发生)。如果您的类具有对其他类实例的引用,则几乎无法估计它。

答案 1 :(得分:1)

在将其放入本地内存缓存之前,我需要了解对象的内存消耗,因此我编写了一个扩展方法,该方法迭代对象的公共属性并总结大小值。如果它是IEnumerable或Array,它将遍历项目并计算其大小。这不是最好的方法,但是对我来说足够好,因为对我的缓存没有比这更复杂的要求了。

    public static class ObjectMemorySizeCalculator
    {
        static int OBJECT_SIZE = IntPtr.Size == 8 ? 24 : 12;
        static int POINTER_SIZE = IntPtr.Size;
        public static long GetMemorySize(this object obj)
        {
            long memorySize = 0;
            Type objType = obj.GetType();

            if (objType.IsValueType)
            {
                memorySize = Marshal.SizeOf(obj);
            }
            else if (objType.Equals(typeof(string)))
            {
                var str = (string)obj;
                memorySize = str.Length * 2 + 6 + OBJECT_SIZE;
            }
            else if (objType.IsArray)
            {
                var arr = (Array)obj;
                var elementType = objType.GetElementType();
                if (elementType.IsValueType)
                {
                    long elementSize = Marshal.SizeOf(elementType);
                    long elementCount = arr.LongLength;
                    memorySize += elementSize * elementCount;
                }                    
                else
                {
                    foreach (var element in arr)
                    {
                        memorySize += element != null ? element.GetMemorySize() + POINTER_SIZE : POINTER_SIZE;
                    }
                }

                memorySize += OBJECT_SIZE;
            }
            else if (obj is IEnumerable)
            {
                var enumerable = (IEnumerable)obj;
                foreach(var item in enumerable)
                {
                    var itemType = item.GetType();
                    memorySize += item != null ? item.GetMemorySize() : 0;
                    if (itemType.IsClass)
                        memorySize += POINTER_SIZE;
                }
                memorySize += OBJECT_SIZE;
            }
            else if (objType.IsClass)
            {
                var properties = objType.GetProperties();
                foreach (var property in properties)
                {
                    var valueObject = property.GetValue(obj);
                    memorySize += valueObject != null ? valueObject.GetMemorySize() : 0;
                    if (property.GetType().IsClass)
                        memorySize += POINTER_SIZE;
                }
                memorySize += OBJECT_SIZE;
            }                

            return memorySize;
        }

答案 2 :(得分:0)

首先,它不是159千字节,而是159字节。甚至空对象占用空间的原因是因为BinaryFormatter也存储了一些元数据。本文提供了一些解释:http://www.codeproject.com/Articles/311944/BinaryFormatter-or-Manual-serializing

要估算解决方案的内存复杂性,可以使用内存分析器。例如,我使用了这个,甚至试用版也很有用:http://www.jetbrains.com/profiler/