C# 收藏与记忆

C# 收藏与记忆,c#,.net,memory,collections,C#,.net,Memory,Collections,我有一个应用程序,它可以读取3-4 GB的数据,从每一行构建实体,然后将它们存储在列表中 我遇到的问题是,内存变得疯狂,变得像13到15GB。为什么存储这些实体会占用这么多内存 所以我建立了一棵树,做了一些类似于哈夫曼编码的事情,总的内存大小变成了200-300MB 我理解,我压缩了数据。但我没想到在列表中存储对象会增加这么多内存。为什么会这样 其他数据结构如字典、堆栈、队列、数组等如何 在哪里可以找到有关数据结构的内部结构和内存分配的更多信息 还是我做错了什么?无论您将使用何种数据结构,您的内

我有一个应用程序,它可以读取3-4 GB的数据,从每一行构建实体,然后将它们存储在列表中

我遇到的问题是,内存变得疯狂,变得像13到15GB。为什么存储这些实体会占用这么多内存

所以我建立了一棵树,做了一些类似于哈夫曼编码的事情,总的内存大小变成了200-300MB

我理解,我压缩了数据。但我没想到在列表中存储对象会增加这么多内存。为什么会这样

其他数据结构如字典、堆栈、队列、数组等如何

在哪里可以找到有关数据结构的内部结构和内存分配的更多信息


还是我做错了什么?

无论您将使用何种数据结构,您的内存消耗永远不会低于存储所有数据所需的内存

您计算过存储一个实例类对象需要多少内存吗

您的huffman编码是一种节省空间的优化,这意味着您自己正在消除类对象中的大量重复数据。这与用于保存数据的数据结构无关。这取决于数据本身的结构,以便您可以利用不同的节省空间策略(其中哈夫曼编码是多种可能性中的一种,适用于消除常见前缀,用于存储数据的数据结构是树)

现在,回到你的问题上来。在不优化数据(即对象)的情况下,有些事情可以提高内存使用效率

我们所有的物体大小都差不多吗

您是否只是简单地运行一个循环,动态分配内存,然后将它们插入列表,如下所示:

foreach (var obj in collection) { myList.Add(new myObject(obj)); }
在这种情况下,列表对象会不断扩展。如果最后没有足够的可用内存来扩展列表,.NET将分配一个新的、更大的内存块,并将原始数组复制到新内存中。基本上,你会得到两块内存——原来的一块和新的扩展的一块(现在保存着列表)。这样做很多次(对于GB的数据,您显然需要这样做),您将看到大量碎片化的内存空间

您最好一次性为整个列表分配足够的内存


作为后记,我忍不住想知道:你到底要如何搜索这个庞大的列表来找到你需要的东西?您不应该使用类似于二叉树或哈希表的东西来帮助您进行搜索吗?也许您只是读取所有数据,对所有数据执行一些处理,然后将它们写回…

无论您将使用何种数据结构,您的内存消耗永远不会低于存储所有数据所需的内存

您计算过存储一个实例类对象需要多少内存吗

您的huffman编码是一种节省空间的优化,这意味着您自己正在消除类对象中的大量重复数据。这与用于保存数据的数据结构无关。这取决于数据本身的结构,以便您可以利用不同的节省空间策略(其中哈夫曼编码是多种可能性中的一种,适用于消除常见前缀,用于存储数据的数据结构是树)

现在,回到你的问题上来。在不优化数据(即对象)的情况下,有些事情可以提高内存使用效率

我们所有的物体大小都差不多吗

您是否只是简单地运行一个循环,动态分配内存,然后将它们插入列表,如下所示:

foreach (var obj in collection) { myList.Add(new myObject(obj)); }
在这种情况下,列表对象会不断扩展。如果最后没有足够的可用内存来扩展列表,.NET将分配一个新的、更大的内存块,并将原始数组复制到新内存中。基本上,你会得到两块内存——原来的一块和新的扩展的一块(现在保存着列表)。这样做很多次(对于GB的数据,您显然需要这样做),您将看到大量碎片化的内存空间

您最好一次性为整个列表分配足够的内存


作为后记,我忍不住想知道:你到底要如何搜索这个庞大的列表来找到你需要的东西?您不应该使用类似于二叉树或哈希表的东西来帮助您进行搜索吗?可能您只是在读取所有数据,对所有数据执行一些处理,然后将它们写回…

如果您使用的是类,请阅读以下内容的响应:

在64位上(您使用的是64位,对吗?),对象开销是16字节加上对对象的引用(有人在引用他,对吗?),所以另外8字节。因此,一个空对象将“吃掉”至少24个字节

如果您使用的是
List
s,请记住
List
s会成倍增长,因此可能会浪费大量空间。其他.NET集合也以同样的方式增长


我要补充的是,数百万的
List
s的“纯”开销可能会让他的记忆崩溃。除了被
列表
对象“吃掉”的16+8字节的空间之外,它(在.NET实现中)由2个整数(8字节)、一个同步锁引用(8字节,通常为空)和一个对内部数组的引用(8+16字节+数组)

如果您使用类,请阅读以下内容的响应:

在64位上(您使用的是64位,对吗?),对象开销是16字节加上对对象的引用(有人在引用他,对吗?),所以另外8字节。因此,一个空对象将“吃掉”至少24个字节

如果您使用的是
列表
s,请记住