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;