我有一个应用程序读取3-4 GB的数据,从每行构建实体,然后将它们存储在列表中。
我遇到的问题是,内存变得疯狂变得像13到15 GB。为什么存储这些实体会占用大量内存。
所以我构建了一个Tree并做了类似于Huffman Encoding的事情,整体内存大小变成了大约200 - 300 MB。
据我所知,我压缩了数据。但我没想到在列表中存储对象会增加内存。为什么会这样?
如字典,堆栈,队列,数组等其他数据结构怎么样?
在哪里可以找到有关数据结构的内部和内存分配的更多信息?
或者我做错了什么?
答案 0 :(得分:2)
在.NET中,大对象会进入未压缩的大对象堆。大是85,000字节以上的一切。当您增加列表时,它们可能会变得比这更大,并且一旦跨越当前容量就必须重新分配。 Rellocation意味着它们很可能放在堆的末尾。所以你最终会得到一个非常分散的LOH和大量的内存使用。
更新:如果您使用所需容量初始化列表(我可以从数据库中确定),那么您的内存消耗应该会有所下降。
答案 1 :(得分:0)
无论您要使用哪种数据结构,您的内存消耗都不会低于存储所有数据所需的内存。
您是否计算过存储一个实例类对象所需的内存量?
您的霍夫曼编码是一种节省空间的优化,这意味着您自己在类对象中消除了大量重复数据。这与用于保存数据的数据结构无关。这取决于您的数据本身的结构,以便您可以利用不同的节省空间的策略(其中霍夫曼编码是许多可能性中的一种,适用于消除公共前缀,用于存储它的数据结构是树)
现在,回到你的问题。在不优化数据(即对象)的情况下,您可以注意一些事项以提高内存使用效率。
我们所有的物体都有相似的大小吗?
您是否只是运行循环,即时分配内存,然后将它们插入到列表中,如下所示:
foreach (var obj in collection) { myList.Add(new myObject(obj)); }
在这种情况下,您的列表对象会不断扩展。如果最后没有足够的可用内存来扩展列表,.NET将为新内存分配一个新的,更大的内存和副本原始数组。基本上你最终得到两块内存 - 原始内存和新扩展内存(现在持有列表)。这样做许多次次(因为你显然需要GB的数据),并且你正在寻找很多的碎片内存空间
你可以一次为整个列表分配足够的内存。
作为一个afternote,我不禁想知道:如何在世界中搜索这个巨大的列表来找到你需要的东西?你不应该使用像二叉树或哈希表这样的东西来帮助你搜索吗?也许你只是阅读所有数据,对所有数据进行一些处理,然后将它们写回来......
答案 2 :(得分:0)
如果您正在使用课程,请阅读以下内容的回复:Understanding CLR object size between 32 bit vs 64 bit
64位(你使用的是64位,对吗?)对象开销是16字节加上对象的引用(有人引用了他,对吗?)所以另外8个字节。所以一个空对象将“吃掉”至少24个字节。
如果你正在使用List
,请记住List
增长一倍,所以你可能会浪费太多空间。其他.NET集合也以同样的方式增长。
我要补充一点,List
百万的“纯粹”开销会让记忆跪倒在地。除了由List
对象“吃掉”的16 + 8字节空间之外,它由2个整数(8个字节)组成(在.NET实现中),一个SyncLock引用(8个字节,通常为空)和对内部数组的引用(所以8 + 16字节+数组)