Python memoryerror创建大字典

时间:2016-04-07 00:36:20

标签: python dictionary memory

我正在尝试处理一个3GB的XML文件,并在循环中获取一个内存错误,该循环读取文件并将一些数据存储在字典中。

class Node(object):
    def __init__(self, osmid, latitude, longitude):
        self.osmid = int(osmid)
        self.latitude = float(latitude)
        self.longitude = float(longitude)
        self.count = 0


context = cElementTree.iterparse(raw_osm_file, events=("start", "end"))
context = iter(context)
event, root = context.next()

for event, elem in context:
    if event == "end" and elem.tag == "node":
        lat = float(elem.get('lat'))
        lon = float(elem.get('lon'))
        osm_id = int(elem.get('id'))
        nodes[osm_id] = Node(osm_id, lat, lon)
        root.clear()

我正在使用迭代解析方法,因此问题不在于读取文件。我只是想将数据存储在字典中以供以后处理,但似乎字典变得太大了。在程序的后面我读了链接,需要检查链接引用的节点是否在初始节点批次中,这就是我将它们存储在字典中的原因。

我怎样才能大大减少内存占用(脚本甚至没有接近完成,因此剃掉碎片并没有多大帮助)或者大大增加了python可用的内存量?监视内存使用情况看起来像python大约在1950 MB左右,而我的计算机仍有大约6 GB的可用内存。

1 个答案:

答案 0 :(得分:3)

假设您创建了大量的Node,您可以考虑使用__slots__为每个Node预定义一组固定的属性。这消除了存储每个实例__dict__的开销(以防止创建未声明的属性),并且可以轻松地将每Node的内存使用量减少~5倍(less on Python 3.3+ where shared key __dict__ reduces the per-instance memory cost for free )。

这很容易做到,只需将Node的声明更改为:

即可
class Node(object):
    __slots__ = 'osmid', 'latitude', 'longitude', 'count'

    def __init__(self, osmid, latitude, longitude):
        self.osmid = int(osmid)
        self.latitude = float(latitude)
        self.longitude = float(longitude)
        self.count = 0

例如,在Python 3.5上(共享密钥字典已经为您节省了一些东西),可以看到对象开销的差异:

 >>> import sys
 >>> ... define Node without __slots___
 >>> n = Node(1,2,3)
 >>> sys.getsizeof(n) + sys.getsizeof(n.__dict__)
 248
 >>> ... define Node with __slots__
 >>> n = Node(1,2,3)
 >>> sys.getsizeof(n)  # It has no __dict__ now
 72

请记住,这是带有共享密钥字典的Python 3.5;在Python 2中,__slots__的每实例成本相似(一个指针大小的变量大于IIRC),而没有__slots__的成本将增加几百个字节。

另外,假设您使用的是64位操作系统,请确保您已安装64位版本的Python以匹配64位操作系统;否则,Python将被限制在~2 GB的虚拟地址空间,而你的6 GB RAM数量非常少。