gpt4 book ai didi

c# - 获取内存中托管对象的 'optimistic' 大小

转载 作者:太空狗 更新时间:2023-10-30 01:35:12 25 4
gpt4 key购买 nike

首先,我知道有很多关于该主题的已发布问题:1 2 3 4 5 .建议的方法和原因:

  • Marshal.SizeOf() 1 - 不适用于托管类型。
  • GC.GetTotalMemory 1 2 - 容易出现竞争条件。
  • 序列化 1 2 3 4 - 非常接近,但是automatic-fields 以及没有的属性可能会出现问题公共(public)二传手。此外,它在性能方面也不是最佳的。
  • 使用 SOS 进行代码分析 1 2 and other tools -很好,但不适用于运行时。

由于填充和发布的问题 1 2 3 ,似乎没有最佳解决方案,而是在精度、性能和代码膨胀之间进行权衡。

但是,我需要简单的方法来计算乐观(最小)内存使用量,即我想知道该对象至少占用了那么多。理由是我拥有拥有许多集合的类型环境,有时是嵌套的,我想快速估计一个对象接近于内存中的 .5 GB 等。

这是我的想法和问题:

  1. 我期待着您的想法和建议做得更好。
  2. 特别是,我正在寻找不是的内存在此代码中说明,并且可能是(无需编写 200 多行的代码)。
  3. 我无法获取自动生成的字段(属性__BackingField) 用于继承的类型,而它适用于非继承的支持字段。我搜索了合适的 BindingFlag,但找不到。

    public static long SizeInBytes<T>(this T someObject)
    {
    var temp = new Size<T>(someObject);
    var tempSize = temp.GetSizeInBytes();
    return tempSize;
    }

    /// <summary>
    /// A way to estimate the in-memory size af any menaged object
    /// </summary>
    /// <typeparam name="TT"></typeparam>
    private sealed class Size<TT>
    {
    private static readonly int PointerSize = Environment.Is64BitOperatingSystem
    ? sizeof(long)
    : sizeof(int);

    private readonly TT _obj;
    private readonly HashSet<object> _references;

    public Size(TT obj)
    {
    _obj = obj;
    _references = new HashSet<object> { _obj };
    }

    public long GetSizeInBytes()
    {
    return GetSizeInBytes(_obj);
    }

    private long GetSizeInBytes<T>(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(short);
    case TypeCode.Int32:
    case TypeCode.UInt32:
    return sizeof(int);
    case TypeCode.Int64:
    case TypeCode.UInt64:
    default:
    return sizeof(long);
    }
    }
    if (obj is decimal)
    {
    return sizeof(decimal);
    }
    if (obj is string)
    {
    return sizeof(char) * obj.ToString().Length;
    }
    if (type.IsEnum)
    {
    return sizeof(int);
    }
    if (type.IsArray)
    {
    long sizeTemp = PointerSize;
    var casted = (IEnumerable)obj;
    foreach (var item in casted)
    {
    sizeTemp += GetSizeInBytes(item);
    }
    return sizeTemp;
    }
    if (obj is Pointer)
    {
    return PointerSize;
    }
    long size = 0;
    var t = type;
    while (t != null)
    {
    size += PointerSize;
    var fields =
    t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic |
    BindingFlags.DeclaredOnly);
    foreach (var field in fields)
    {
    var tempVal = field.GetValue(obj);
    if (!_references.Contains(tempVal))
    {
    _references.Add(tempVal);
    size += GetSizeInBytes(tempVal);
    }
    }
    t = t.BaseType;
    }
    return size;
    }
    }

[编辑]

这个问题的结果是 Nugetcp article

最佳答案

要回答有关获取字段的第三个问题,您可以可靠地获取如下类型的所有字段:

    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;
}
}

这是有效的,因为 GetFields 可以返回当前 Type 的私有(private)字段,但不能返回任何继承的私有(private)字段;因此您需要在每个 Type 上沿着继承链调用 GetFields

关于c# - 获取内存中托管对象的 'optimistic' 大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26835656/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com