python中的cPickle.load()占用大量内存

python中的cPickle.load()占用大量内存,python,memory,pickle,Python,Memory,Pickle,我有一本大词典,其结构如下: dcPaths = {'id_jola_001': CPath instance} 其中CPath是一个自定义类: class CPath(object): def __init__(self): # some attributes self.m_dAvgSpeed = 0.0 ... # a list of CNode instance self.m_lsNodes = []

我有一本大词典,其结构如下:

dcPaths = {'id_jola_001': CPath instance}
其中CPath是一个自定义类:

class CPath(object):
    def __init__(self):
        # some attributes
        self.m_dAvgSpeed = 0.0
        ...
        # a list of CNode instance
        self.m_lsNodes = []
class CApp(object):
    def __init__(self):
        # some attributes
        self.m_nCount= 0
        self.m_nUpPackets = 0
其中m_lsNodes是CNode的列表:

class CNode(object):
    def __init__(self):
        # some attributes
        self.m_nLoc = 0

        # a list of Apps
        self.m_lsApps = []
这里,m_lsApps是CApp的列表,它是另一个自定义类:

class CPath(object):
    def __init__(self):
        # some attributes
        self.m_dAvgSpeed = 0.0
        ...
        # a list of CNode instance
        self.m_lsNodes = []
class CApp(object):
    def __init__(self):
        # some attributes
        self.m_nCount= 0
        self.m_nUpPackets = 0
我使用cPickle序列化此词典:

def serialize2File(strFileName, strOutDir, obj):
    if len(obj) != 0:
        strOutFilePath = "%s%s" % (strOutDir, strFileName)
        with open(strOutFilePath, 'w') as hOutFile:
            cPickle.dump(obj, hOutFile, protocol=0)
        return strOutFilePath
    else:
        print("Nothing to serialize!")
它工作正常,序列化文件的大小约为6.8GB。但是,当我尝试反序列化此对象时:

def deserializeFromFile(strFilePath):
    obj = 0
    with open(strFilePath) as hFile:
        obj = cPickle.load(hFile)
    return obj
我发现它消耗了超过90GB的内存,而且需要很长时间

  • 为什么会发生这种情况
  • 我有没有办法优化这个

  • 顺便说一句,我使用的是Python2.7.6

    当您存储复杂的python对象时,python通常会存储大量无用的数据(请查看
    \uuu dict\uu
    对象属性)

    为了减少未序列化数据的内存消耗,应该只pickle python本机。在类上实现一些方法可以很容易地实现这一点:
    object.\uuu getstate\uuuu()
    object.\uuuu setstate\uuuu(state)


    请参阅python文档。

    您可以尝试指定pickle协议;最快的是-1(意思是:最新的 协议,如果使用相同的Python版本进行酸洗和取消酸洗,则没有问题)

    编辑: 正如评论中所说:
    load
    检测协议本身

    cPickle.load(obj, file)
    

    进程在将数据转储到pickle之前消耗了多少内存?这可能取决于存储类的定义方式,因此添加代码会有所帮助。确定是反序列化吗?众所周知,序列化会占用相当多的内存来处理循环引用。1。你能告诉我们:哪种类型的物体最常用?2.您能用最低的协议转储它并显示/链接一些较小的块吗?3.你使用Python3吗?4.如果使用pickle,问题是否仍然存在?@bereal我添加了存储类的代码
    \uuuu dict\uuuu
    是表示python对象的标准方法,在pickle之前也会存在,因此,这并不能解释内存增加的原因。@KillianDS但是很多引用的内容也被序列化了,因为不可能在新环境中将对自定义对象的引用更新为它们的新副本。Pickle做了一些魔术来最小化这种影响(在模块级别解析类型),但是不需要的实例(如单例)在取消Pickle时被序列化和复制。我可以使用protocol=0转储并使用protocol=-1加载吗?因为我已经用protocol=0转储了数据,现在的问题是如何将其加载回?此外,我在cPickle.load()中找不到协议参数。@ice_lin
    load
    检测到协议本身,您只能在
    dump
    /
    dumps
    上指定它。但是协议0不是很有效,至少可以部分解释您看到的问题。@ice_lin:加载协议0转储的数据,然后使用协议=-1重新转储它们。。。