C# 在c中查找对象实例的大小(以字节为单位)#
对于任意实例(不同对象的集合、组合、单个对象等) 如何确定其大小(以字节为单位) (我目前有一个各种对象的集合,我正在尝试确定它的聚合大小)C# 在c中查找对象实例的大小(以字节为单位)#,c#,C#,对于任意实例(不同对象的集合、组合、单个对象等) 如何确定其大小(以字节为单位) (我目前有一个各种对象的集合,我正在尝试确定它的聚合大小) 编辑:是否有人为对象编写了一个扩展方法来执行此操作?这在我看来相当不错。这在运行时是不可能做到的 不过,有各种内存分析器可以显示对象大小 编辑:您可以编写第二个程序,使用分析第一个程序,并通过远程处理或其他方式与之通信。好的,如果不以字节为单位深入计算每个成员的大小,您就不能。但同样,成员的大小(如集合中的元素)是否计入对象的大小,或者指向该成员的指针是否
编辑:是否有人为对象编写了一个扩展方法来执行此操作?这在我看来相当不错。这在运行时是不可能做到的 不过,有各种内存分析器可以显示对象大小
编辑:您可以编写第二个程序,使用分析第一个程序,并通过远程处理或其他方式与之通信。好的,如果不以字节为单位深入计算每个成员的大小,您就不能。但同样,成员的大小(如集合中的元素)是否计入对象的大小,或者指向该成员的指针是否计入对象的大小?这取决于你如何定义它 我以前遇到过这样的情况,我想根据对象消耗的内存限制缓存中的对象
好吧,如果有什么诀窍可以做到这一点,我很高兴知道 您可以使用反射来收集所有公共成员或属性信息(给定对象的类型)。但是,如果不遍历对象上的每个单独数据段,就无法确定大小。这不适用于当前的.NET实现,但在垃圾收集/管理的运行时中需要记住的一点是,对象的分配大小可以在程序的整个生命周期内更改。例如,某些分代垃圾收集器(如)只需要在对象从托儿所移动到成熟空间后存储某些信息
这使得不可能创建一个可靠的通用API来公开对象大小。如果使用可序列化对象,则可以通过假装使用二进制序列化程序对其进行序列化(但将输出路由到oblivion)来近似大小
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();
}
}
类程序
{
静态void Main(字符串[]参数)
{
父母;
家长=新A(1,“迈克”);
父项。添加子项(“Greg”);
父母。AddChild(“Peter”);
父母。孩子(“博比”);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf=
新的System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
SerializationSizer ss=新的SerializationSizer();
bf.序列化(ss,父级);
WriteLine(“序列化对象的大小为{0}”,ss.Length);
}
}
[可序列化()]
甲级
{
int-id;
字符串名;
列出儿童名单;
公共A(整数id,字符串名称)
{
this.id=id;
this.name=名称;
children=新列表();
}
公共B AddChild(字符串名称)
{
B newItem=新的B(此,名称);
添加(newItem);
返回新项目;
}
}
[可序列化()]
B类
{
父母;
字符串名;
公共B(父级,字符串名称)
{
this.parent=parent;
this.name=名称;
}
}
类SerializationSizer:System.IO.Stream
{
私有整数总大小;
公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数)
{
this.totalSize+=计数;
}
公共覆盖布尔可读取
{
获取{return false;}
}
公共覆盖布尔搜索
{
获取{return false;}
}
公共覆盖布尔可写
{
获取{return true;}
}
公共覆盖无效刷新()
{
//无事可做
}
公共覆盖长长度
{
获取{return totalSize;}
}
公众优先多头仓位
{
得到
{
抛出新的NotImplementedException();
}
设置
{
抛出新的NotImplementedException();
}
}
公共重写整型读取(字节[]缓冲区、整型偏移量、整型计数)
{
抛出新的NotImplementedException();
}
公共覆盖长寻道(长偏移,System.IO.SeekOrigin原点)
{
抛出新的NotImplementedException();
}
公共覆盖无效设置长度(长值)
{
抛出新的NotImplementedException();
}
}
对于值类型,可以使用。当然,它返回在非托管内存中封送结构所需的字节数,这不一定是CLR所使用的。首先,警告:下面的内容严格属于丑陋的、未记录的黑客领域。不要依赖于此工作-即使它现在对您有效,明天它可能会停止工作,任何次要或主要的.NET更新
您可以使用本文中关于CLR内部结构的信息—上次我检查时,它仍然适用。这是如何做到的(它通过类型的TypeHandle
检索内部“基本实例大小”字段)
object obj=new List();//无论你想要什么尺寸的
RuntimeTypeHandle th=obj.GetType().TypeHandle;
整数大小=*(*(整数**)和th+1);
控制台写入线(大小);
这适用于3.5 SP1 32位。我不确定64位上的字段大小是否相同-如果不相同,您可能需要调整类型和/或偏移量
这将适用于所有“普通”类型,对于这些类型,所有实例都具有相同的、定义良好的类型。对于那些不是这样的数组和字符串,我也相信StringBuilder
。对于它们,您必须将所有包含元素的大小添加到它们的基本实例大小。使用带有命令的ObjSize
请注意,由于直接位于对象数据之前的synkblk
,实际消耗的内存始终大于ObjSize
报告
请在此处阅读有关这两种类型的详细信息。对于非托管类型,即值类型,结构:
Marshal.SizeOf(object);
对于托管对象,我得到的是近似值
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;
long start_mem=GC.getTotalMemy(true);
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;
/* 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
private static long? GetSizeOfObjectInBytes(object item)
{
if (item == null) return 0;
try
{
// hackish solution to get an approximation of the size
var jsonSerializerSettings = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
MaxDepth = 10,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var formatter = new JsonMediaTypeFormatter { SerializerSettings = jsonSerializerSettings };
using (var stream = new MemoryStream()) {
formatter.WriteToStream(item.GetType(), item, stream, Encoding.UTF32);
return stream.Length / 4; // 32 bits per character = 4 bytes per character
}
}
catch (Exception)
{
return null;
}
}
private int DumpApproximateObjectSize(object toWeight)
{
return Marshal.ReadInt32(toWeight.GetType().TypeHandle.Value, 4);
}
Testing with string: 1234567
Hashtable<TestObject>: 184 672 704 B
Hashtable<TestObjectRef>: 136 668 560 B
Dictionary<int, TestObject>: 171 448 160 B
Dictionary<int, TestObjectRef>: 123 445 472 B
ConcurrentDictionary<int, TestObject>: 200 020 440 B
ConcurrentDictionary<int, TestObjectRef>: 152 026 208 B
HashSet<TestObject>: 149 893 216 B
HashSet<TestObjectRef>: 101 894 384 B
ConcurrentBag<TestObject>: 112 783 256 B
ConcurrentBag<TestObjectRef>: 64 777 632 B
Queue<TestObject>: 112 777 736 B
Queue<TestObjectRef>: 64 780 680 B
ConcurrentQueue<TestObject>: 112 784 136 B
ConcurrentQueue<TestObjectRef>: 64 783 536 B
ConcurrentStack<TestObject>: 128 005 072 B
ConcurrentStack<TestObjectRef>: 80 004 632 B
GC.GetAllocatedBytesForCurrentThread()
first = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0).ToInt64();
second = Marshal.UnsafeAddrOfPinnedArrayElement(array, 1).ToInt64();
arrayElementSize = second - first;