1

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

在 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获取字段的大小(以字节为单位)

我有一个 class 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 应用程序

4

3 回答 3

3

在将对象放入 Local In-Memory-Cache 之前,我需要知道它的内存消耗,所以我编写了一个扩展方法,它遍历对象的公共属性并总结大小值。如果它是 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;
        }
于 2020-10-06T10:59:42.757 回答
1

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

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

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

于 2013-08-17T16:32:00.403 回答
0

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

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

于 2013-08-17T16:29:21.390 回答