【问题标题】:Python memoryerror creating large dictionaryPython memoryerror 创建大字典
【发布时间】:2016-07-27 15:46:38
【问题描述】:

我正在尝试处理一个 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。

【问题讨论】:

  • 你运行的是 64 位 Python 吗?
  • 天哪,我以为我只是检查了一下,实际上我使用的是 32。据我了解,32 对内存使用量有硬性限制,但 64 没有,对吧?跨度>
  • 64 位也有硬性上限,但您不太可能达到它,因为它是 TB 的倍数。
  • @user2913671:64 位也有硬上限。但它至少大了 256 倍(所以 512 GB 而不是 2 GB 的地址空间),我认为此时它通常大 65536 倍(所以 128 TB 的地址空间,我很确定应该足够了)。 :-)

标签: python dictionary memory


【解决方案1】:

假设您创建了大量的Nodes,您可以考虑使用__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 非常少。

【讨论】:

  • 这很棒!大量减少内存使用并切换到 64 位版本给了我仍然需要的额外 GB。谢谢!
猜你喜欢
  • 2016-07-11
  • 1970-01-01
  • 2014-10-02
  • 2019-08-07
  • 2016-11-20
  • 2016-08-24
  • 2021-06-25
  • 2023-03-15
  • 1970-01-01
相关资源
最近更新 更多