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

本文关键字:对象 查找 内存 | 更新日期: 2023-09-27 18:27:58

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

在c中查找对象实例的大小(以字节为单位)#http://www.codeproject.com/Questions/177604/Size-of-a-class-in-c如何在内存中获取对象大小?使用C获取字段的大小(以字节为单位)#http://blogs.msdn.com/b/cbrumme/archive/2003/04/15/51326.aspx

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

[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大小是159k字节,但我认为这是不正确的方式,一个空物体不能有这样的大小,是真的吗?

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

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

在将对象放入本地内存缓存之前,我需要了解对象的内存消耗情况,因此我编写了一个扩展方法,该方法遍历对象的公共属性并汇总大小值。如果它是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;
        }

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

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

您还可以通过将字段的大小计算为下限来估计大小(因为会出现填充)。如果您的类引用了其他类实例,那么估计起来几乎是不可能的。

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

要估计解决方案的内存复杂性,可以使用内存探查器。例如,我使用了这个,即使是试用版也很有用:http://www.jetbrains.com/profiler/.