【问题标题】:How to force Python dictionary to shrink?如何强制 Python 字典缩小?
【发布时间】:2015-07-15 23:23:52
【问题描述】:

我在其他语言中也经历过。现在我在 Python 中遇到了同样的问题。我有一本包含很多 CRUD 操作的字典。有人会假设从字典中删除元素应该会减少它的内存占用。事实并非如此。一旦字典的大小增加(通常翻倍),它就永远不会(?)释放分配的内存。我已经运行了这个实验:

import random
import sys
import uuid

a= {}
for i in range(0, 100000):
    a[uuid.uuid4()] = uuid.uuid4()
    if i % 1000 == 0:
        print sys.getsizeof(a)

for i in range(0, 100000):
    e = random.choice(a.keys())
    del a[e]
    if i % 1000 == 0:
        print sys.getsizeof(a)

print len(a)

第一个循环的最后一行是6291736。第二个循环的最后一行也是6291736。字典的大小是0

那么如何解决这个问题呢?有没有办法强制释放内存?

PS:真的不需要随机 - 我玩的是第二个循环的范围。

【问题讨论】:

  • 您可以尝试使用旧字典的内容创建一个新字典,并删除对旧字典的引用。
  • 什么时候?按照时间表?如何阻止写入?
  • Python 的 threadingmultiprocessingasyncio 模块 all 为您提供几乎相同的同步原语,例如 Lock。我会开始查看适用模块的文档。
  • 另外,6291736 是 6MB。您的应用程序的内存占用现在是个问题吗?过早调试是万恶之源……
  • 确实如此。只要您从字典中删除条目,它们就会被重用。 6 MB 看起来不错。你想通过释放这个内存来解决什么问题?顺便说一句,即使你设法从 Python 手中撬开它,它也可能永远不会被释放回操作系统。

标签: python dictionary memory-management garbage-collection


【解决方案1】:

执行这种“重新散列”以减少内存使用的方法是创建一个新字典并复制内容。

这个视频很好地解释了 Python 字典的实现:

https://youtu.be/C4Kc8xzcA68

有一位与会者提出同样的问题(https://youtu.be/C4Kc8xzcA68?t=1593),发言人给出的答案是:

仅在插入时计算调整大小;随着字典的缩小,它只会获得很多虚拟条目,并且当您重新填充时,它只会开始重用这些条目来存储密钥。 [...] 您必须将键和值复制到新字典中

【讨论】:

  • 我不能停止一切——请求以异步方式传入。当然,Python 异步模型是有问题的,但不能保证当我将数据从一个字典移动到另一个字典时,源字典不会有任何变化。
  • 这看起来很像 stop-the-world 垃圾回收,并且以同样的方式,您可以使用 Lock 以便异步请求在重新创建 dict 时等待。更多关于锁的信息:docs.python.org/2/library/threading.html
  • @Schultz9999 然后你需要像任何异步编程一样考虑锁定等。在内部,列表使用数组。它随着项目的增加而增长。要遍历并压缩列表(本质上是对数组进行“碎片整理”)将需要阻塞其他线程。
  • 好吧,你可以停止一切。使用 Python 的 many concurrency models 中的任何一个同步原语可能会阻止字典被更新。
【解决方案2】:

实际上字典可以在调整大小时缩小,但调整大小只发生在键插入而不是删除时。这是CPython sourcedictresize 的评论:

通过分配一个新表并重新插入所有表来重组表 再次项目。删除条目后,新表可能 实际上比旧的要小。

顺便说一句,由于其他答案在 PyCon 2010 的字典中引用了 Brandon Rhodes talk,并且该引用似乎与上述内容不一致(已经存在多年),我想我会包括完整的引用, 缺少的部分以粗体显示。

仅在插入时计算调整大小。随着字典的缩小, 它只是获得了很多虚拟条目,当你重新填充它时,它会 只需开始重新使用它们来存储密钥。 它不会调整大小,直到你 设法使其更大的尺寸再次充满三分之二。所以 删除键时不会调整大小。你必须做一个插入才能得到 它找出它需要缩小。

所以他确实说调整大小操作可以“找出 [字典] 需要缩小”。但这仅在插入时发生。显然,在调整大小期间复制所有键时,可以删除虚拟键,从而减小后备数组的大小。

然而,如何做到这一点尚不清楚,这就是为什么 Rhodes 说将所有内容复制到新字典中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多