Python memoryerror 创建大字典

标签 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 的可用 RAM。

最佳答案

假设您要创建大量的 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 的值(value)很小。

关于Python memoryerror 创建大字典,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36464704/

相关文章:

python - 如果某个键相同,则获取所有值的平均值

c - 如何更改连续地址的内存?

python - 从 S3 下载透明背景文件

c# - 根据键对字典列表进行排序

python - 获取字典中匹配键的值

javascript - 仅在 IE9 标准模式下的 asp.net javascript 内存泄漏

arrays - MIPS:将用户输入字符串与内存中的字符串数组进行比较

python - 在 matplotlib + numpy 中布置几个图

python - statistics.mean() vs sum()/len() vs np.average() 对于列表列表

python - 利用 "Copy-on-Write"将数据复制到 Multiprocessing.Pool() 工作进程