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

Posted

技术标签:

【中文标题】我可以找出导致我的 Python MemoryError 的分配请求吗?【英文标题】:Can I find out the allocation request that caused my Python MemoryError? 【发布时间】:2019-02-24 17:32:57 【问题描述】:

上下文

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

最好不深入库的深度,我想弄清楚是否值得在具有更多内存的不同机器上尝试此算法,或者尝试减少我的输入大小,或者它是否丢失导致我尝试使用的数据大小。

问题

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

【问题讨论】:

这是对 MemoryError: airbrake.io/blog/python-exception-handling/memoryerror 的一个很好的概述。您使用的 DP 库是什么?超大输入的大小是多少?与博客文章中的强制越界类似,您可以尝试循环遍历并根据 N 分配内存,然后将其丢弃,直到失败。这会告诉你 N 在哪里发生故障。至于您的直接问题,“如何调查我的代码尝试分配导致错误的内存大小”,我没有立即看到任何明显的东西。有趣的问题! @ScottSkiles,此时我的实际问题或多或少已通过近似/概率解决方案得到解决,这只是我对 Python 中错误对象的好奇。上下文只是为了弄清楚为什么人们可能会关心这个问题,并且大多与实际问题分开。该算法用于计算近似子字符串匹配的 Levenshtein 距离的变体,我的数据(如果我没记错的话)大约有一百万个字符。 从@ScottSkiles 引用的文章看来,您似乎可以在错误处理中使用psutil.virtual_memory() 来获取您正在寻找的内存使用数据。也就是说,我不知道根据您的问题从错误本身获取此信息的方法。 @ScottSkiles @benvc 如果你们中的任何一个愿意将关于psutil 的事实转化为答案,我很乐意接受并奖励赏金。 @benvc 继续。我正在旅行。 【参考方案1】:

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

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

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

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

【讨论】:

【参考方案2】:

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

    在本地克隆包。

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

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

【讨论】:

【参考方案3】:

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

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

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

这是有道理的——如果没有记忆怎么办?

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

【讨论】:

以上是关于我可以找出导致我的 Python MemoryError 的分配请求吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何找出导致冲突的 Git 提交?

(permutation/Anagrm) 在 python 2.72 中找到的单词(需要帮助来找出我的代码有啥问题)

如何找出 Oracle 死锁的原因

用 Python 找出了拉黑 QQ 空间屏蔽我的大人物

用 Python 找出了拉黑 QQ 空间屏蔽我的大人物

试图在种子方法中的 SaveChanges 中找出我的验证错误