Python内存序列化

Mar*_*tyn 10 python serialization memory-management class pickle

我想知道是否有人可能知道以下答案.

我正在使用Python来构建基于字符的后缀树.树中有超过1100万个节点,可以容纳大约3GB的内存.这通过使用slot类方法而不是Dict方法从7GB下降.

当我序列化树(使用最高协议)时,生成的文件要小一百多倍.

当我重新加载pickle文件时,它再次消耗3GB的内存.这个额外开销来自何处,是否与Pythons处理对类实例的内存引用有关?

更新

感谢larsmans和Gurgeh提供的非常有用的解释和建议.我正在使用树作为文本语料库中信息检索界面的一部分.

我最初将子项(最多30个)存储为Numpy数组,然后尝试硬件版本(ctypes.py_object*30),Python数组(ArrayType),以及字典和集类型.

列表似乎做得更好(使用孔雀鱼来描述内存,并且__slots__['variable',...]),但是如果可以的话,我仍然试图将它压缩一点.我对数组唯一的问题是必须事先指定它们的大小,这导致只有一个子节点的节点有点冗余,而且我有很多它们.;-)

在构造树之后,我打算将它转换为具有第二遍的概率树,但是可以在构造树时执行此操作.由于构造时间在我的情况下并不太重要,所以array.array()听起来像是有用的东西,感谢提示,真的很感激.

我会告诉你它是怎么回事.

Fre*_*Foo 9

如果你试图挑选一个空列表,你会得到:

>>> s = StringIO()
>>> pickle.dump([], s)
>>> s.getvalue()
'(l.'
Run Code Online (Sandbox Code Playgroud)

并且类似地'(d.'为空dict.这是三个字节.该列表的内存中表示,但是,包含

  • 引用计数
  • 类型ID,反过来包含指向内存分配的类型名称和簿记信息的指针
  • 指向实际元素指针向量的指针
  • 还有更多的簿记信息.

在我的机器上,它有64位指针,sizeof一个Python列表头对象是40个字节,所以这是一个数量级.我假设一个空的dict将具有相似的大小.

然后,两者listdict使用一个过度分配策略来获得其主要操作的摊销O(1)性能,malloc引入开销,对齐,您可能或可能不知道的成员属性以及各种其他因素,使您获得二阶大小.

总结:pickle是一个非常好的Python对象压缩算法:)