在内存管理对象获取'乐观'大小 [英] Get 'optimistic' size of managed object in memory
问题描述
首先,我知道很多贴涵盖主题的问题:<一href="http://stackoverflow.com/questions/3533785/how-to-measure-the-amount-of-memory-an-individual-object-takes-in-net">1 2 的 3 <一href="http://stackoverflow.com/questions/1128315/find-size-of-object-instance-in-bytes-in-c-sharp">4 5 。所提出的方法和放大器;为什么不:
- Marshal.SizeOf() 1 - 不为menaged工种
- GC.GetTotalMemory 1 的 2 - 竞争条件容易。
- 连载 1 2 3 4 - 这是相当接近,但 自动字段可以是有问题的,以及无属性 公众制定者。此外,它不是最佳的性能,明智的。 使用SOS 1 的在code分析http://stackoverflow.com/a/三百九十二万二千二百九十二分之七百十二万二千六百五十三> 2 等工具 - 伟大的,但不适合运行。
由于填充和问题张贴 1 的 2 3 ,它的出现,也没有最优解,而之间的权衡precision,性能和code-膨胀。
不过,我需要简单的方法来算乐观(最小)内存使用情况,也就是我想知道的对象至少占据的那么多的。的理由是,我有类型拥有众多的收藏品,有时嵌套的环境,我想快速逼近,一个对象即将接近,即0.5 GB的内存等。
还有就是我想出了和放大器;我的问题:
- 我期待着您的想法和建议,对什么都可以 可以做的更好。
- 特别是,我在寻找记忆,是不是 在这code占了,可(无需编写200+线 的code本)。
-
我不能自动生成的字段(财产
__ BackingField
)的遗传类型,而它工作正常不继承后备字段。我寻找合适的BindingFlag,但未能找到。///&LT;总结&gt; ///找实例占用的最小内存量。 ///算都是实例字段,包括自动生成的,private和protected。 ///不计:任何静态字段,任何属性,功能,动作,成员方法等。 ///&LT; /总结&gt; 公共静态长SizeInBytes&LT; T&GT;(这件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&LT;字段信息&GT; GetAllFields(T型)
{
而(T!= NULL)
{
的foreach(在t.GetFields(字段信息领域BindingFlags.Instance | BindingFlags.NonPublic可| BindingFlags.Public | BindingFlags.DeclaredOnly))
{
得到的回报场;
}
T = t.BaseType;
}
}
这工作,因为 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
.
这篇关于在内存管理对象获取'乐观'大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!