c#数组的内存分配

来源:互联网 发布:代谢综合征临床数据库 编辑:程序博客网 时间:2024/05/21 09:43

引起我对这个题目的兴趣的原因是这样的,有客户抱怨公司的产品运行时out of memory了,于是我便开始研究这个问题到底出在什么地方。


当时程序的运行状态是这样的,一共有10000个数组(请尽情吐槽程序的结构设计),第一个数组中有6个object,第二个数组有12个object,以此类推,第10000个数组有60000个object。整个程序中该object的数量只有60000个,也就是说第一个数组中的6个object就是最后一个数组的前六个object。


当调试到这里,我立刻想到,难道是60000个object导致了OOM?

于是使用了dotTrace发现这6W个object只占了几百M的内存,而OOM异常起码内存占用要超过2G。


到底是什么东西占用了这么大的内存?

想着这个问题时,突然眼睛瞟到dotTrace内存报告中显示object[]占用了极大的内存,超过了那6w个object。至此,总算找到了OOM的原因:大量的数组占用了大量的内存。与此同时,另外一个问题又出现了。


数组为何会占用如此大量的内存?object数组存储的应该仅仅只是object的地址,地址怎么会占用这么大的内存?对于这个问题,我百思不得其解。


一开始,我以为是ArrayList的内存开辟,因为ArrayList可以动态更改数组长度,也就会动态的开辟内存,而每次内存开辟是在上一次的数组长度上乘2,于是我使用了TrimToSize()方法来削减多余开辟的内存,问题仍然没有解决。


不甘心的我直接将ArrayList改成object[],当然,大家应该可以预见,问题仍不会得到解决。


无计可施的我最后只能求助于google,数组的内存分配到底是怎样的。于是查到了这样一篇文章:

http://stackoverflow.com/questions/487202/memory-layout-of-a-net-array

在回复里面,有人详细解答了数组的内存分配。

大致是这样说的:

对于一个32位的程序

  • 数组的前4个byte保存method table地址.
  • 接下来4个byte保存数组长度.
  • 再下来就是数组的元素,每个对象的地址,需要4个bytes.
  • 最后4个byte为空。不是非常确定,但是猜测是用来保存syncblock数组的引用当实例被lock住的时候


这样一来,我根据这个信息简单计算了一下程序里面大量数组所占用的内存:

10000个数组,总共占用了N个bytes来保存对象的地址

N=(6+12+18+……+60000)*4=1200120000

N约为1个G


到了这里我才恍然大悟,别小看对象的地址这小小的4个byte,在糟糕的程序结构设计,变态用户的需求等条件下,一切皆有可能。

原创粉丝点击