2,147,483,648 doubles 的数组将占用 16GB 内存。对某些人来说,这没什么大不了的。如果我分配其中一些数组,我的服务器甚至都不会费心点击页面文件。并不意味着这是个好主意。
当您处理这样的大量数据时,您应该尽量减少进程对内存的影响。有几种方法可以解决这个问题,具体取决于您处理数据的方式。
稀疏数组
如果您的数组是稀疏填充的 - 大量默认/空值和一小部分实际有效/有用的数据 - 那么稀疏数组可以大大减少内存需求。您可以编写各种实现来优化不同的分布配置文件:随机分布、分组值、任意连续组等。
适用于任何类型的包含数据,包括复杂的类。有一些开销,因此当填充百分比很高时,实际上可能比裸数组更差。当然,您仍将使用内存来存储实际数据。
简单的平面文件
将数据存储在磁盘上,为文件创建一个读/写FileStream,并将其封装在一个包装器中,让您可以像访问内存数组一样访问文件的内容。最简单的实现将为您从文件中顺序读取提供合理的用途。随机读取和写入可能会减慢您的速度,但您可以在后台进行一些缓冲以帮助缓解速度问题。
这种方法适用于任何具有静态大小的类型,包括可以复制到/从文件中的字节范围复制的结构。不适用于字符串等动态大小的数据。
复杂的平面文件
如果您需要处理动态大小的记录、稀疏数据等,那么您也许可以设计一种可以优雅地处理它的文件格式。再说一次,此时数据库可能是更好的选择。
内存映射文件
与其他文件选项相同,但使用不同的机制来访问数据。有关如何使用 .NET 中的内存映射文件的更多信息,请参阅 System.IO.MemoryMappedFile。
数据库存储
根据数据的性质,将其存储在数据库中可能对您有用。然而,对于大量 doubles 来说,这不太可能是一个很好的选择。在数据库中读取/写入数据的开销,加上存储开销 - 每行将至少需要有一个行标识,对于大型记录集可能是 BIG_INT(8 字节整数),加倍数据的大小立即生效。加上索引、行存储等的开销,您可以很容易地增加数据的大小。
数据库非常适合存储和处理复杂的数据。这就是他们的目的。如果您有可变宽度数据(字符串等),那么数据库可能是您最好的选择之一。另一方面,它们通常不是处理大量非常简单的数据的最佳解决方案。
无论您选择哪种方式,您都可以创建一个 IList<T> 兼容的类来封装您的数据。这让您编写的代码不需要知道如何数据是存储的,只需要知道它是什么。