我有一个包含字符串和长对的1GB文件.将它读入字典的最佳方法是什么,你说它需要多少内存?
文件有6200万行.我已经设法用5.5GB的ram读取它.
假设每个Dictionary条目的开销为22字节,即1.5GB.long是8个字节,即500MB.平均字符串长度为15个字符,每个字符2个字节,即2GB.总计大约4GB,额外的1.5 GB到哪里去了?
初始字典分配需要256MB.我注意到我读取的每1000万行消耗大约580MB,这与上面的计算完全吻合,但在6000行左右,内存使用量从260MB增加到1.7GB,这是我缺少的1.5GB,它在哪里走?
谢谢.
了解填充Hashtable时发生的情况非常重要.(The Dictionary使用Hashtable作为其底层数据结构.)
当您创建新的Hashtable时,.NET会生成一个包含11个存储桶的数组,这些存储桶是字典条目的链接列表.添加条目时,其密钥将被哈希处理,哈希代码将映射到11个桶中的一个,并且条目(键+值+哈希码)将附加到链接列表中.
在某一点(这取决于首次构造Hashtable时使用的负载因子),Hashtable在Add操作期间确定它遇到了太多的冲突,并且最初的11个桶是不够的.因此它创建了一个新的桶数组,其大小是旧数据块的两倍(不完全是;桶的数量总是为素数),然后从旧表中填充新表.
因此,在内存利用方面有两件事情可以发挥作用.
首先,Hashtable每隔一段时间就需要使用两倍于目前使用的内存,以便在调整大小时可以复制表.所以如果你有一个使用1.8GB内存的Hashtable并且它需要调整大小,那么它需要使用3.6GB,而且,现在你遇到了问题.
第二个是每个哈希表条目有大约12个字节的开销:指向密钥的指针,值和列表中的下一个条目,加上哈希码.对于大多数用途,这种开销是微不足道的,但是如果你正在构建一个包含1亿条目的Hashtable,那么这大约是1.2GB的开销.
您可以通过使用Dictionary的构造函数的重载来解决第一个问题,该构造函数可以提供初始容量.如果您指定的容量足以容纳您将要添加的所有条目,则在填充Hashtable时不需要重建Hashtable.关于第二个,你几乎无能为力.
这里的每个人似乎都同意,处理这个的最好方法是一次只将一部分文件读入内存.当然,速度取决于存储器中的哪个部分以及当需要特定信息时必须从磁盘读取哪些部分.
有一种简单的方法来处理决定保留在内存中的最佳部分:
将数据放入数据库.
一个真实的,如MSSQL Express,或MySql或Oracle XE(都是免费的).
数据库缓存最常用的信息,因此就像从内存中读取一样.它们为您提供了内存或磁盘数据的单一访问方法.
也许您可以将该1 GB文件转换为具有两列键和值的SQLite数据库.然后在键列上创建索引.之后,您可以查询该数据库以获取您提供的密钥的值.