我可以找出导致 Python MemoryError 的分配请求吗?

Can I find out the allocation request that caused my Python MemoryError?

上下文

我的小 Python 脚本使用一个库来处理一些相对较大的数据。此任务的标准算法是动态规划算法,因此大概“幕后”库分配了一个大数组来跟踪 DP 的部分结果。事实上,当我尝试给它相当大的输入时,它会立即给出 MemoryError.

最好不要深入库的深处,我想弄清楚是否值得在具有更多内存的不同机器上尝试这个算法,或者尝试 trim 降低我的输入大小,或者如果它是我尝试使用的数据大小的失败原因。

问题

当我的 Python 代码抛出 MemoryError 时,是否有一种“自上而下”的方式让我调查我的代码试图分配的内存大小是什么导致了错误,例如通过检查错误对象?

MemoryError 似乎没有使用任何关联数据创建:

def crash():
    x = 32 * 10 ** 9
    return 'a' * x

try:
    crash()
except MemoryError as e:
    print(vars(e))  # prints: {}

这是有道理的——如果没有内存怎么办?

我认为没有捷径可走。您可以从 MemoryError 导致的回溯开始,并使用调试器进行调查,或者使用像 pympler 这样的内存分析器(或评论中建议的 psutil)。

MemoryError异常中看不到,异常是针对任何内存分配失败的情况引发的,包括Python内部不要直接连接到创建新 Python 数据结构的代码;一些模块创建锁或其他支持对象,这些操作可能会由于内存 运行 不足而失败。

您也不一定知道要使整个操作成功需要多少内存。如果库在操作过程中创建了多个数据结构,尝试为用作字典键的字符串分配内存可能是最后一根稻草,或者它可能复制整个现有数据结构以进行变异,或介于两者之间的任何事情,但是此外,这并没有说明该过程的其余部分需要多少内存。

也就是说,Python 可以使用 tracemalloc module 为您提供有关正在进行哪些内存分配以及何时何地进行的详细信息。使用该模块和实验方法,您可以估计完成数据集需要多少内存。

诀窍是找到可以可以完成过程的数据集。您可能想要找到不同大小的数据集,然后可以测量 那些 数据结构需要多少内存。您可以在这些数据集的快照之间使用 tracemalloc.take_snapshot(), compare differences and statistics 前后创建快照,也许您可​​以从该信息推断出更大的数据集需要多少内存。当然,这取决于操作的性质和数据集,但如果存在任何一种模式,tracemalloc 是发现它的最佳机会。

您可以使用 Pyampler 查看内存分配,但您需要在您正在使用的库中本地添加调试语句。假设一个标准的 PyPi 包,这里是步骤:

  1. 在本地克隆包。

2 使用 Pyampler 的 summary module。在主递归方法中放置以下内容,

   from pympler import summary
   def data_intensive_method(data_xyz)
       sum1 = summary.summarize(all_objects)
       summary.print_(sum1)
       ...
  1. 运行 pip install -e . 在本地安装编辑好的包。
  2. 运行 您的主程序并在每次迭代时检查控制台的内存使用情况。