获取';乐观的';内存中托管对象的大小
本文关键字:对象 内存 乐观 获取 | 更新日期: 2023-09-27 18:29:59
首先,我知道许多发布的问题涉及该主题:1 2 3 4 5。建议的方法&为什么不:
- Marshal.SizeOf()1-不适用于托管类型
- GC.GetTotalMemory 1 2-容易出现比赛情况
- 序列化1 2 3 4-非常接近,但是自动字段和没有公共设置者。此外,它并不是最佳性能
- 使用SOS 1 2和其他工具进行代码分析-很棒,但不适用于运行时
由于1 2 3发布的填充和问题,似乎没有最佳解决方案,而是在精度、性能和代码膨胀之间进行权衡。
然而,我需要一个简单的方法来计算乐观(最小)内存使用量,即我想知道对象至少占用那么多。基本原理是,我有一个类型拥有许多集合的环境,有时是嵌套的,我想快速估计一个对象即将接近,即内存等中的.5GB
这是我想出的&我的问题:
- 我期待您的想法和建议做得更好
- 特别是,我在寻找不是在该代码中说明,并且可以(在不写入200多行的情况下的代码)
-
无法获取自动生成的字段(属性
__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; } }
[EDIT]
这个问题导致了Nuget和cp文章
要回答关于获取字段的第三个问题,您可以可靠地获取以下类型的所有字段:
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
的私有字段,但不能返回任何继承的私有字段;因此,您需要在每个Type
上调用GetFields
的继承链上遍历。