我有一个形式为lst = [('xxx', 'yyy'), ...etc]
的字符串元组的python列表。该列表大约有8154741
个元组。我使用了一个分析器,它说该列表在内存中大约需要500 MB。
然后我将列表中的所有元组写入文本文件,磁盘大小占用大约72MB。
我有三个问题:
为什么内存消耗与磁盘使用不同?
为这样的列表消耗500MB的内存是否合乎逻辑?
是否有减少列表大小的方法/技巧?
答案 0 :(得分:3)
你有8154741
个元组,这意味着你的列表,假设有8个字节的指针,已经包含62 MB
指向元组的指针。
假设每个元组在python2中包含两个ascii字符串,那就是每个元组的另一个124 MB
指针。
然后你仍然有元组和字符串对象的开销,每个对象都有一个引用计数,假设这是一个8字节整数,你有另一个186 MB
引用计数存储。对于大小为2元组的两个3字节长字符串的372 MB
数据,这已经是46 MB
的开销。
在python3下,您的数据是unicode,每个字符也可能大于1个字节。
所以是的,预计这种结构会占用大量的内存。
如果你的字符串都具有相似的长度并且元组都具有相同的长度,则减少这种情况的方法是使用numpy字符串数组。它们将字符串存储在一个连续的内存块中,避免了对象开销。但是,如果字符串的大小变化很大,因为numpy不支持不规则的数组,这将无法正常工作。
>>> d = [("xxx", "yyy") for i in range(8154741)]
>>> a = numpy.array(d)
>>> print a.nbytes/1024**2
46
>>> print a[2,1]
yyy
答案 1 :(得分:2)
Python对象可以比其中的原始数据占用更多内存。这是因为要实现Python的高级和超高速数据结构的功能,您必须创建一些中间和临时对象。 阅读更多here。
解决此问题有多种方法,请参阅案例研究here。在大多数情况下,为您的应用程序找到最合适的python数据类型就足够了(在您的情况下使用numpy数组而不是列表会不会更好?)。要进行更多优化,您可以转到Cython,您可以直接声明变量的类型(以及大小),例如C语言。
还有像IOPro这样的软件包试图优化内存使用(这个是商业用途,有人知道免费软件包吗?)。
答案 2 :(得分:0)
字符串大部分是共享的还是唯一的? 元组有什么意义:词袋或跳过克表示? 如果是这样,一个用于单词矢量表示的好库是word2vec
这是一个很好的article on optimizing word2vec's performance
您是否真的需要将字符串内容保留在内存中,或者只是转换为功能向量,并将字符串< - >功能对应写入磁盘?