C# 获取';乐观的';内存中托管对象的大小
首先,我知道有很多问题都涉及到这个主题:。提议的方法&为什么不:C# 获取';乐观的';内存中托管对象的大小,c#,.net,memory,memory-management,C#,.net,Memory,Memory Management,首先,我知道有很多问题都涉及到这个主题:。提议的方法&为什么不: Marshal.SizeOf()-不适用于托管类型 GC.GetTotalMemory-易受竞争条件影响 序列化-非常接近,但是 自动字段可能会有问题,没有自动字段的属性也可能会有问题 公众设定者。此外,它在性能方面也不是最优的 使用SOS进行代码分析- 很好,但不适用于运行时 由于填充和发布的问题,似乎没有最佳解决方案,而是在精度、性能和代码膨胀之间进行权衡 然而,我需要一种简单的方法来计算乐观(最小)内存使用量,即我想知道
- Marshal.SizeOf()-不适用于托管类型
- GC.GetTotalMemory-易受竞争条件影响李>
- 序列化-非常接近,但是 自动字段可能会有问题,没有自动字段的属性也可能会有问题 公众设定者。此外,它在性能方面也不是最优的李>
- 使用SOS进行代码分析- 很好,但不适用于运行时
\uuuu 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;
}
}
publicstaticlong-SizeInBytes(这个T-someObject)
{
var temp=新大小(someObject);
var tempSize=temp.GetSizeInBytes();
返回时间长度;
}
///
///一种估计任何菜单对象的内存大小的方法
///
///
私人密封班级人数
{
私有静态只读int PointerSize=Environment.Is64BitOperatingSystem
?尺寸(长)
:sizeof(int);
私有只读TT_obj;
私有只读哈希集\u引用;
公共规模(TT obj)
{
_obj=obj;
_references=newhashset{u obj};
}
公共长GetSizeInBytes()
{
返回GetSizeInBytes(_obj);
}
专用长GetSizeInBytes(T obj)
{
if(obj==null)返回sizeof(int);
var type=obj.GetType();
if(类型为IsPrimitive)
{
开关(类型.GetTypeCode(类型))
{
大小写类型代码。布尔值:
大小写类型代码。字节:
案例类型代码.SByte:
返回sizeof(字节);
case TypeCode.Char:
返回sizeof(char);
案例类型代码。单个:
返回sizeof(浮动);
案例类型代码。双:
返回sizeof(双倍);
case TypeCode.Int16:
案例类型代码.UInt16:
返回sizeof(短);
case TypeCode.Int32:
案例类型代码.UInt32:
返回sizeof(int);
case TypeCode.Int64:
案例类型代码.UInt64:
违约:
返回sizeof(长);
}
}
if(对象为十进制)
{
返回sizeof(十进制);
}
if(obj是字符串)
{
返回sizeof(char)*obj.ToString().Length;
}
if(type.IsEnum)
{
返回sizeof(int);
}
如果(键入IsArray)
{
long-sizeTemp=PointerSize;
var casted=(IEnumerable)obj;
foreach(铸造中的var项目)
{
sizeTemp+=GetSizeInBytes(项目);
}
返回sizeTemp;
}
if(obj是指针)
{
返回点个性化;
}
长尺寸=0;
var t=类型;
while(t!=null)
{
大小+=指针大小;
变量字段=
t、 GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic|
绑定标志(仅限声明);
foreach(字段中的变量字段)
{
var tempVal=field.GetValue(obj);
if(!\u references.Contains(tempVal))
{
_参考文献。添加(tempVal);
size+=GetSizeInBytes(tempVal);
}
}
t=t.BaseType;
}
返回大小;
}
}
此问题导致和要回答关于获取字段的第三个问题,您可以可靠地获取以下类型中的所有字段:
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;
}
}
公共静态IEnumerable GetAllFields(类型t)
{
while(t!=null)
{
foreach(t.GetFields中的FieldInfo字段(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
产量回报场;
}
t=t.BaseType;
}
}
这是因为
GetFields
可以返回当前类型的私有字段,但不能返回任何继承的私有字段;因此,您需要沿着继承链向上走,在每个类型上调用GetFields
,可能太宽,因为“可能的答案太多,或者好的答案对于这种格式来说太长。请添加详细信息以缩小答案集,或者隔离一个可以在几段中回答的问题”与所有条件语句相比,使用重载来处理基元类型可能更简单。您应该将GetTypeCode
与switch/case一起使用,以避免出现瀑布式的情况。尝试使用循环引用计算对象的大小总是很有趣的…:)在计算字符串的大小时,还必须考虑长度成员的大小。因此,它应该是sizeof(char)*string.Length+sizeof(int)。