在内存管理对象获取'乐观'大小内存管理、乐观、对象、大小

2023-09-04 01:12:12 作者:大大大大爱.//

首先,我知道很多贴涵盖主题的问题:1 2 的 3 4 5 。所提出的方法和放大器;为什么不:

Marshal.SizeOf() 1 - 不为menaged工种 GC.GetTotalMemory 1 的 2 - 竞争条件容易。 连载 1 2 3 4 - 这是相当接近,但 自动字段可以是有问题的,以及无属性 公众制定者。此外,它不是最佳的性能,明智的。 使用SOS 1 的 2 等工具 - 伟大的,但不适合运行。

由于填充和问题张贴 1 的 2 3 ,它的出现,也没有最优解,而之间的权衡precision,性能和code-膨胀。

不过,我需要简单的方法来算乐观(最小)内存使用情况,也就是我想知道的对象至少占据的那么多的。的理由是,我有类型拥有众多的收藏品,有时嵌套的环境,我想快速逼近,一个对象即将接近,即0.5 GB的内存等。

还有就是我想出了和放大器;我的问题:

我期待着您的想法和建议,对什么都可以 可以做的更好。 特别是,我在寻找记忆,是不是 在这code占了,可(无需编写200+线 的code本)。

我不能自动生成的字段(财产 __ BackingField )的遗传类型,而它工作正常不继承后备字段。我寻找合适的BindingFlag,但未能找到。

  ///<总结>
///找实例占用的最小内存量。
///算都是实例字段,包括自动生成的,private和protected。
///不计:任何静态字段,任何属性,功能,动作,成员方法等。
///< /总结>
公共静态长SizeInBytes< T>(这件T OBJ)
{
    如果(OBJ == NULL)返回的sizeof(INT);
    VAR类型= obj.GetType();
    如果(type.IsPrimitive)
    {
       开关(Type.GetType code(类型))
        {
            案件类型code.Boolean:
            案件类型code.Byte:
            案件类型code.SByte:
                返回的sizeof(字节);
            案件类型code.Char:
                返回的sizeof(字符);
            案件类型code.Single:
                返回的sizeof(浮动);
            案件类型code.Double:
                返回的sizeof(双);
            案件类型code.Int16:
            案件类型code.UInt16:
                返回的sizeof(Int16的);
            案件类型code.Int32:
            案件类型code.UInt32:
                返回的sizeof(的Int32);
            案件类型code.Int64:
            案件类型code.UInt64:
            默认:
                返回的sizeof(Int64的);
        }
    }
    否则,如果(obj为十进制)
    {
        返回的sizeof(十进制);
    }
    否则,如果(obj是字符串)
    {
        返回的sizeof(char)的* obj.ToString()长度。
    }
    否则,如果(type.IsEnum)
    {
        返回的sizeof(INT);
    }
    否则,如果(type.IsArray)
    {
        长尺寸= sizeof的(INT);
        VAR铸造=(IEnumerable的)目标文件;
        的foreach(在铸造VAR项)
        {
            大小+ = item.SizeInBytes();
        }
        返回的大小;
    }
    其他
    {
        长大小= 0;
        VAR T =类型;
        而(T!= NULL)
        {
            的foreach(在t.GetFields(VAR场BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic可| BindingFlags.DeclaredOnly))
            {
                VAR tempVal = field.GetValue(OBJ);
                如果(!object.ReferenceEquals(OBJ,tempVal))
                {
                    大小+ = tempVal.SizeInBytes();
                }
            }
            T = t.BaseType;
        }
        返回的大小;
    }
}
 

解决方案

要回答你的第三个问题有关获取的字段,可以可靠地得到这样的类型的所有字段:

 公共静态的IEnumerable<字段信息> GetAllFields(T型)
    {
        而(T!= NULL)
        {
            的foreach(在t.GetFields(字段信息领域BindingFlags.Instance | BindingFlags.NonPublic可| BindingFlags.Public | BindingFlags.DeclaredOnly))
            {
                得到的回报场;
            }
            T = t.BaseType;
        }
    }
 
讲一下JVM堆内存管理 对象分配过程

这工作,因为 GetFields 可以返回当前的私有字段键入,但没有任何继承私有字段;所以你需要走上继承链调用 GetFields 每个键入

First, I am aware of many posted questions covering the topic: 1 2 3 4 5. The proposed approaches & why not:

Marshal.SizeOf() 1 - does not work for menaged types. GC.GetTotalMemory 1 2 - race condition prone. Serialization 1 2 3 4 - it's quite close, but automatic-fields can be problematic, as well as properties without public setter. Also, it's not optimal performance-wise. Code profiling using SOS 1 2 and other tools - great, but not for runtime.

Due to padding and issues posted 1 2 3, it appears, there is no optimal solution, rather trade-off between precision, performance and code-bloat.

However, I needed simple method to count optimistic (minimum) memory usage, i.e. I want to know that the object occupies at least that much. The rationale is that I have the environment of types owning many collections, sometimes nested, and I want to approximate quickly, that an object is coming close to i.e. .5 GB in memory etc..

There is what I came up with & my questions:

I am looking forward for Your thoughts and suggestions on what can be done better. Especially, I'm looking for memory that is not accounted for in this code, and could be (without writing 200+ lines of code for this).

I can't get auto generated fields (property __BackingField) for inherited type, whilst it works fine for not inherited backing fields. I searched for proper BindingFlag, but could not find one.

/// <summary>
/// Get the minimal memory amount occupied by instance.
/// Counted are all instance fields, including auto-generated, private and protected.
/// Not counted: any static fields, any properties, functions, actions, member methods etc.
/// </summary>
public static long SizeInBytes<T>(this T obj)
{
    if (obj == null) return sizeof(int);
    var type = obj.GetType();
    if (type.IsPrimitive)
    {
       switch (Type.GetTypeCode(type))
        {
            case TypeCode.Boolean:
            case TypeCode.Byte:
            case TypeCode.SByte:
                return sizeof(byte);
            case TypeCode.Char:
                return sizeof(char);
            case TypeCode.Single:
                return sizeof(float);
            case TypeCode.Double:
                return sizeof(double);
            case TypeCode.Int16:
            case TypeCode.UInt16:
                return sizeof(Int16);
            case TypeCode.Int32:
            case TypeCode.UInt32:
                return sizeof(Int32);
            case TypeCode.Int64:
            case TypeCode.UInt64:
            default:
                return sizeof(Int64);
        }
    }
    else if (obj is decimal)
    {
        return sizeof(decimal);
    }
    else if (obj is string)
    {
        return sizeof(char) * obj.ToString().Length;
    }
    else if (type.IsEnum)
    {
        return sizeof(int);
    }
    else if (type.IsArray)
    {
        long size = sizeof(int);
        var casted = (IEnumerable)obj; 
        foreach (var item in casted)
        {
            size += item.SizeInBytes();
        }
        return size;
    }
    else
    {
        long size = 0;
        var t = type;
        while (t != null)
        {
            foreach (var field in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
            {
                var tempVal = field.GetValue(obj);
                if (!object.ReferenceEquals(obj,tempVal))
                {
                    size += tempVal.SizeInBytes();
                }
            }
            t = t.BaseType;
        }
        return size;
    }
}

解决方案

To answer your third question about getting fields, you can reliably get all fields in a type like this:

    public static IEnumerable<FieldInfo> GetAllFields(Type t)
    {
        while (t != null)
        {
            foreach (FieldInfo field in t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly))
            {
                yield return field;
            }
            t = t.BaseType;
        }
    }

This works because GetFields can return the private fields of the current Type, but not any inherited private fields; so you need to walk up the inheritance chain calling GetFields on each Type.