如何计算托管对象的大小

想知道这个,原因就一个:85000bytes以上的对象对于GC性能影响较大。我用sqlprofier监视过一些我们自己的biz entity,不过,runtime监视,不爽。。。

查了不少资料,李建忠老师的blog看了(问题出来了,还没有答案,期待ing...),google了一下:how to get a managed object size?找到了一个blog,在这里: http://blogs.msdn.com/cbrumme/archive/2003/04/15/51326.aspx

.net不提供SizeOf(manged obj)接口的原因我认为很简单,主要考虑alignment。
在看这个blog之前,我自己写了一段代码,也能大致的计算出来,不过我考虑得比较简单。
None.gif //  销售订单,内嵌一个客户类
None.gif
     public   class  BillOrder
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
private byte[] bindata;
InBlock.gif        
private int num;
InBlock.gif        
private Customer customer;
InBlock.gif        
InBlock.gif        
public int id;
InBlock.gif
InBlock.gif        
public BillOrder(int size)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            id 
= 200;
InBlock.gif            bindata 
= new byte[size];
InBlock.gif            
for(int i=0;i<size;i++)bindata[i] = (byte)'A';
InBlock.gif            num 
= 20;
InBlock.gif            customer 
= new Customer("juqiang",123.4567f);
InBlock.gif            
InBlock.gif            
InBlock.gif            Console.WriteLine(
"Create a "+size.ToString()+" bytes billorder ");
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

None.gif //  客户,内嵌一个地址结构体
None.gif
     public   class  Customer
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
private float limit;
InBlock.gif        
private string name;
InBlock.gif        
private Address address;
InBlock.gif
InBlock.gif        
public Customer(string name, float limit)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this.name = name;
InBlock.gif            
this.limit = limit;
InBlock.gif            address 
= new Address();
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

None.gif //  地址结构体
None.gif
     public   struct  Address
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
string addr;
InBlock.gif        
string postal;
InBlock.gif        
string contacter;
ExpandedBlockEnd.gif    }

生成一个销售订单对象
None.gif BillOrder bo1  =   new  BillOrder( 1000000 );

好了,到此为止,我们要计算bo1的占用内存的大小。看我的第一个原始版本代码:
None.gif //  对于nested对象,递归调用。
None.gif
//  这里为了测试,只是简单的用了几个类型
None.gif
         private   static   int  Calc( object  o)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif            FieldInfo[] filist 
= o.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
InBlock.gif            
if(filist.Length<1)return -1;
InBlock.gif            
InBlock.gif            
int ret = 0;
InBlock.gif
InBlock.gif            
foreach(FieldInfo fi in filist)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
int len = 0;
InBlock.gif                
int len2 = -1;
InBlock.gif                
try
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
//object o2 = Activator.CreateInstance(fi.GetType());
InBlock.gif
                    object o2 = fi.GetValue(o);
InBlock.gif                    Type t2 
= o2.GetType();
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
if(o2 is System.Int32)dot.gif{len=4;goto end;}
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
else if(o2 is System.Byte)dot.gif{len = 1;goto end;}
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
else if(o2 is System.Int32[])dot.gif{len = ((byte[])o2).Length*4;goto end;}
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
else if(o2 is System.Byte[])dot.gif{len= ((byte[])o2).Length;goto end;}
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
else if(o2 is System.String)dot.gif{len= Convert.ToString(o2).Length;goto end;}
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
else if(o2 is System.Single)dot.gif{len = 4;goto end;}
InBlock.gif                    
else 
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        Console.WriteLine(
"Below is "+o2.GetType().Name);
InBlock.gif                        len2 
= Calc(o2);
InBlock.gif                        Console.WriteLine(
"end of "+o2.GetType().Name+"(Total) --- "+len2.ToString());
ExpandedSubBlockEnd.gif                    }

InBlock.gif                end:
InBlock.gif                    ret 
+= len;
InBlock.gif                    
if(len2>-1)ret += len2;
InBlock.gif                    Console.WriteLine(fi.Name
+" --- "+len.ToString());
ExpandedSubBlockEnd.gif                }

InBlock.gif                
catch
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif            
InBlock.gif            
InBlock.gif            
return ret;
ExpandedBlockEnd.gif        }

利用此方法,这么调用:
None.gif int  size  =  Calc(bo1);
得到的结果是:
Create a 1000000 bytes billorder
Create a 1000000 bytes billorder
bindata --- 1000000
num --- 4
Below is Customer
limit --- 4
name --- 7
Below is Address
end of Address(Total) --- 0
address --- 0
end of Customer(Total) --- 11
customer --- 0
id --- 4
1000019
就是说,这个对象大小,我这么粗略的计算,是1000019个字节。(上面没有考虑到字节对齐)

ok,其实上面那篇老外的blog,提到了一嘴,可以clone一个同样的object,然后计算两者指针的偏移。
然后看这段代码,我废了不少劲才写出来, hitwall.gif
None.gif //  首先再new一个同样的销售订单出来
None.gif
BillOrder bo1  =   new  BillOrder( 1000000 );
None.gifBillOrder bo2 
=   new  BillOrder( 1000000 );
None.gif
//  然后。。。
None.gif
GCHandle h1   =  GCHandle.Alloc(bo1);
None.gifGCHandle h2 
=  GCHandle.Alloc(bo2);
ExpandedBlockStart.gifContractedBlock.gif
unsafe dot.gif {
InBlock.gif    
int* i1 = (int*)(((IntPtr)h1).ToPointer());
InBlock.gif    
int* i2 = (int*)(((IntPtr)h2).ToPointer());
InBlock.gif                
InBlock.gif    
int off1 = *((int*)((new IntPtr(*i1+4)).ToPointer()));
InBlock.gif    
int off2 = *((int*)((new IntPtr(*i2+4)).ToPointer()));
InBlock.gif    Console.WriteLine(
"Size is:"+(off2-off1).ToString());
ExpandedBlockEnd.gif}

上面代码中,其实就是指针->指针->偏移+4这么一个转化。这个值,我是从debug-memory里面,“猜测”出来的,呵呵。没有仔细分析过clr header,所以我不知道它的原理。
好了,用上面的方法,我们得到的大小是:Size is:1000032。
我相信,这应该是一个中规中矩的销售订单的占用内存大小。

欢迎各位高手指教!

转载于:https://www.cnblogs.com/juqiang/archive/2005/08/17/217141.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值