在c#中查找以字节为单位的对象实例的大小

对于任何实例(不同对象,构图,单个对象等的集合)

我怎样才能确定它的大小以字节为单位?

(我目前有各种对象的集合,我试图确定它的聚合大小)

编辑:有人写了可以做到这一点的对象的扩展方法? 这将是相当整齐的艾莫。

首先,警告:严格来说,这是丑陋的,无证的黑客行为。 不要依赖这个工作 – 即使它现在适用于你,它可能会在明天停止工作,任何次要或重大的.NET更新。

你可以在CLR内部使用这篇文章中的信息 – 最后我检查了一下,它仍然适用。 这是如何完成的(它通过TypeHandle检索内部“基本实例大小”字段)。

 object obj = new List<int>(); // whatever you want to get the size of RuntimeTypeHandle th = obj.GetType().TypeHandle; int size = *(*(int**)&th + 1); Console.WriteLine(size); 

这适用于3.5 SP1 32位。 我不确定字段大小在64位上是否相同 – 如果不是,您可能需要调整types和/或偏移量。

这将适用于所有“常规”types,所有实例都具有相同的,明确定义的types。 那些不是真正的数组和string,我相信也是StringBuilder 。 对于他们来说,你将所有包含的元素的大小添加到他们的基本实例大小。

如果你正在使用可序列化的对象,你可以通过假装序列化一个二进制串行器(但是将输出路由到遗忘)来估计大小。

 class Program { static void Main(string[] args) { A parent; parent = new A(1, "Mike"); parent.AddChild("Greg"); parent.AddChild("Peter"); parent.AddChild("Bobby"); System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); SerializationSizer ss = new SerializationSizer(); bf.Serialize(ss, parent); Console.WriteLine("Size of serialized object is {0}", ss.Length); } } [Serializable()] class A { int id; string name; List<B> children; public A(int id, string name) { this.id = id; this.name = name; children = new List<B>(); } public B AddChild(string name) { B newItem = new B(this, name); children.Add(newItem); return newItem; } } [Serializable()] class B { A parent; string name; public B(A parent, string name) { this.parent = parent; this.name = name; } } class SerializationSizer : System.IO.Stream { private int totalSize; public override void Write(byte[] buffer, int offset, int count) { this.totalSize += count; } public override bool CanRead { get { return false; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return true; } } public override void Flush() { // Nothing to do } public override long Length { get { return totalSize; } } public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public override int Read(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } public override long Seek(long offset, System.IO.SeekOrigin origin) { throw new NotImplementedException(); } public override void SetLength(long value) { throw new NotImplementedException(); } } 

对于非托pipetypes又名值types,结构体:

  Marshal.SizeOf(object); 

对于pipe理对象,我得到的是近似值。

  long start_mem = GC.GetTotalMemory(true); aclass[] array = new aclass[1000000]; for (int n = 0; n < 1000000; n++) array[n] = new aclass(); double used_mem_median = (GC.GetTotalMemory(false) - start_mem)/1000000D; 

不要使用序列化。二进制格式化程序会添加标题,因此您可以更改类并将旧的序列化文件加载到修改后的类中。

也不会告诉你在内存中的实际大小,也不会考虑内存alignment。

[编辑]通过在你的类的每个属性上recursion地使用BiteConverter.GetBytes(prop-value),你将获得以字节为单位的内容,这不包括类或引用的权重,但更接近现实。 我build议使用字节数组的数据和非托pipe代理类访问值使用指针铸造如果大小的问题,请注意,这将是不alignment的内存,所以在旧计算机会慢,但巨大的数据集在MODERN RAM将是速度要快得多,因为从RAM中读取的大小最小化将比未校准的更大。

这不适用于当前的.NET实现,但要记住垃圾收集/pipe理的运行时是一个对象的分配的大小可以改变整个程序的整个生命周期。 例如,一些代代垃圾收集器(如Generational / Ulterior Reference Counting Hybrid收集器 )只需要在将对象从幼儿园移动到成熟空间之后存储某些信息。

这使得不可能创build一个可靠的通用API来公开对象大小。

这在运行时是不可能的。

虽然有各种显示对象大小的内存分析器。

编辑 :你可以编写第二个程序,configuration文件的第一个使用CLR分析API,并通过远程处理或与其通信。

AFAIK,你不能真正深入计算每个成员的字节大小。 但是,成员的大小(如集合中的元素)是否会计入对象的大小,或者指向该成员的指针是否会计入对象的大小? 取决于你如何定义它。

我已经遇到了这种情况之前,我想根据他们消耗的内存限制在我的caching中的对象。

那么,如果有这样的伎俩,我会很高兴知道!

对于值types,可以使用Marshal.SizeOf 。 当然,它将返回非托pipe内存中编组结构所需的字节数,这不一定是CLR所使用的。

安全的解决scheme和一些优化Cyber​​Saving / MemoryUsage代码 。 有些情况下:

 /* test nullable type */ TestSize<int?>.SizeOf(null) //-> 4 B /* test StringBuilder */ StringBuilder sb = new StringBuilder(); for (int i = 0; i < 100; i++) sb.Append("わたしわたしわたしわ"); TestSize<StringBuilder>.SizeOf(sb ) //-> 3132 B /* test Simple array */ TestSize<int[]>.SizeOf(new int[100]); //-> 400 B /* test Empty List<int>*/ var list = new List<int>(); TestSize<List<int>>.SizeOf(list); //-> 205 B /* test List<int> with 100 items*/ for (int i = 0; i < 100; i++) list.Add(i); TestSize<List<int>>.SizeOf(list); //-> 717 B 

它也适用于类:

 class twostring { public string a { get; set; } public string b { get; set; } } TestSize<twostring>.SizeOf(new twostring() { a="0123456789", b="0123456789" } //-> 28 B 

您可以使用reflection收集所有的公共成员或属性信息(给定对象的types)。 不过,如果不通过对象上的每个单独的数据,就无法确定大小。

使用具有命令ObjSize Strike of Son 。

请注意,由于synkblk直接位于对象数据之前,因此实际消耗的内存总是大于ObjSize报告。

阅读更多关于这里http://msdn.microsoft.com/en-us/magazine/cc163791.aspx

我的课没有标记为可序列化,所以这里的一些答案没有奏效。 我像这样绕了一圈。

 var dump = JsonConvert.SerializeObject(obj);