对于任何任意实例(不同对象,组合,单个对象等的集合)
如何确定其大小(以字节为单位)?
(我现在有各种对象的集合,我正在尝试确定它的聚合大小)
编辑:有人写了一个可以做到这一点的对象的扩展方法吗?那个非常整洁的imo.
Pav*_*aev 56
首先,一个警告:接下来的内容严格地说是丑陋的,无证件的黑客攻击.不要依赖于这项工作 - 即使它现在适用于您,它可能会在明天停止工作,任何次要或主要的.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);
Run Code Online (Sandbox Code Playgroud)
这适用于3.5 SP1 32位.我不确定64位上的字段大小是否相同 - 如果不是,则可能需要调整类型和/或偏移量.
这适用于所有"普通"类型,所有实例都具有相同的,定义良好的类型.那些不成对的是数组和字符串肯定,我也相信StringBuilder.对于它们,您将把所有包含元素的大小添加到它们的基本实例大小.
Blu*_*kMN 19
如果您正在使用可序列化对象,则可以通过假装使用二进制序列化程序对其进行序列化(但将输出路由到遗忘)来近似大小.
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();
}
}
Run Code Online (Sandbox Code Playgroud)
对于非托管类型,也就是值类型,结构:
Marshal.SizeOf(object);
Run Code Online (Sandbox Code Playgroud)
对于托管对象,我得到的更接近是近似值.
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;
Run Code Online (Sandbox Code Playgroud)
不要使用序列化.二进制格式化程序会添加标题,因此您可以更改类并将旧的序列化文件加载到已修改的类中.
它也不会告诉你内存中的实际大小,也不会考虑内存对齐.
[编辑]通过在类的每个属性上递归使用BiteConverter.GetBytes(prop-value),您将获得以字节为单位的内容,这不会计算类或引用的权重,但更接近现实.如果大小很重要,我建议使用字节数组进行数据和非托管代理类使用指针转换来访问值,请注意这将是非对齐内存,因此在旧计算机上会很慢但是在MODERN RAM上的巨大数据集将会是更快,因为最小化从RAM读取的大小将比未对齐更大的影响.
这不适用于当前的.NET实现,但要记住垃圾收集/托管运行时的一件事是对象的分配大小可以在程序的整个生命周期中发生变化.例如,一些世代垃圾收集器(例如Generational/Ulterior Reference Counting Hybrid收集器)仅需要在将对象从托儿所移动到成熟空间之后存储某些信息.
这使得无法创建可靠的通用API来公开对象大小.
小智 5
经过优化的安全解决方案 CyberSaving / 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
Run Code Online (Sandbox Code Playgroud)
它也适用于类:
class twostring
{
public string a { get; set; }
public string b { get; set; }
}
TestSize<twostring>.SizeOf(new twostring() { a="0123456789", b="0123456789" } //-> 28 B
Run Code Online (Sandbox Code Playgroud)
不直接回答问题,但对于那些有兴趣在调试时调查对象大小的人:
这在运行时是不可能做到的。
不过,有多种内存分析器可以显示对象大小。
编辑:您可以编写第二个程序,使用CLR Profiling API来分析第一个程序,并通过远程处理或其他方式与其进行通信。
| 归档时间: |
|
| 查看次数: |
88672 次 |
| 最近记录: |