如何在 Python 中处理内存错误?

2024 年 8 月 29 日 | 阅读 6 分钟

MemoryError 表示 Python 解释器已经耗尽了我们 Python 程序的内存分配。这可能是由于 Python 环境设置的问题,或者是程序本身一次性加载过多内容的问题。

什么是内存错误?

Python 内存错误,或者更通俗地说,我们程序的 RAM 内存空间已耗尽,无法继续执行。

这个问题最可能的原因是将所有数据加载到系统内存中。对于大型数据集,建议使用批处理。与其将完整数据放入内存,不如将其保留在硬盘上,并分块检索。

内存错误表明我们的软件已达到其内存限制。这意味着我们的软件生成了过多的对象。在这种情况下,我们必须查找程序中可能占用大量 RAM 的区域。

当任务耗尽存储空间时,就会发生内存错误。

内存错误示例

让我们从一段非常贪婪的代码开始,看看这个问题是如何发生的。在下面的脚本中,我们从一个空列表开始,并通过嵌套列表向其中添加 Python 字符串。在这种情况下,使用三个嵌套列表层,每个层有十亿次迭代。这意味着程序运行后,列表将包含字符串“More”十亿次重复。

代码

输出

C:\code\Python\MemErr\venv\3K\Scripts\Python.exe C:/code/Python/MemErr/main.py
Traceback (most recent call last):
  File "C:/code/Python/MemErr/main.py", line 6, in <module>
   
s.append("More")
MemoryError

由于这个小程序没有包含任何模块,因此回溯错误非常简单。在显示了触发问题的特定函数调用的回溯之后,我们看到了基本但直接的 MemoryError。

处理内存错误的方法

适当的 Python 设置

最简单但也许最不明显的 MemoryError 解决方案是处理 Python 设置可能存在的问题。如果我们在一台 64 位机器上安装了 32 位版本的 Python 应用程序,我们将只能有限地访问系统的 RAM。这种有限的访问可能导致我们在计算机应能正常处理的程序上出现内存错误。

注意大型嵌套循环

如果 Python 安装是足够的,但这些问题仍然存在,则可能需要重新考虑代码。遗憾的是,除了分析和优化我们的代码之外,没有简单的解决方案可以消除这个问题。密切关注任何大型或嵌套循环,以及每次我们一次性加载大量数据集到我们的程序中,就像上面的例子一样。

在这些情况下,将工作分成几组通常是可取的,从而允许在调用之间释放 RAM。例如,在下面的程序中,我们将之前的嵌套循环分成了三个独立的循环,每个循环运行 333,333,333 次迭代。该程序仍然运行了一百万次,但由于我们可以通过垃圾收集器清空内存,因此它不再抛出 MemoryError。

请参阅以下嵌套循环批处理示例

代码

如何限制内存和 CPU 使用率

现在我们将看到如何限制运行程序的内存或 CPU 使用率,以防止内存错误。通过使用 Resource 模块,我们可以同时完成这两项任务,如以下代码所示

代码

输出

The time limit is exceeded by the program
An exception has occurred; use %tb to see the full traceback.

SystemExit: 1

代码限制了整体地址空间以控制内存消耗。

代码

输出

Memory limit is exceeded by the code

避免 Python 中的内存错误

程序中内存错误最常见的原因是在处理大型数据集时。在处理机器学习项目时,我们经常遇到大型数据集,当执行回归或聚类的机器学习算法时,会导致计算机 RAM 立即耗尽。我们可以通过运行生成器函数来解决此类问题。在处理大型数据集时,它可以实现为用户定义的函数。

无需导入整个数据集,Python 生成器函数就可以轻松地将大型数据集分成多个部分。生成器在处理大量数据行的大型项目时非常有用。生成器函数返回迭代器对象。可以使用这些迭代器对象循环遍历数据。典型的迭代器方法是在 Python 循环中编写的,并迭代整个数据集。这时生成器函数就很有帮助了,它避免了对整个数据集的循环,因为这样做会导致内存错误并导致应用程序崩溃。

Python 中的生成器函数与其他常规函数不同,因为它在通常返回函数结果的常规 return 关键字处包含一个名为 yield 的关键字。但是,yield 命令执行后,它不会终止函数。

提供了一个生成器函数示例

代码

使用关系数据库

关系数据库可以存储和一致地访问大型数据集。

从根本上说,数据存储在磁盘上,可以通过标准的查询语言进行访问,并分批(SQL)加载。

大多数(所有?)计算机语言和几个机器学习应用程序都可以轻松地与关系数据库连接,例如开源数据库解决方案 MySQL 或 Postgres。此外,SQLite 这样的轻量级方法也是一个选择。

结论

我们已经详细介绍了 Python 编程语言中的内存错误以及处理名称错误的方法。关于内存错误,最重要的事情是了解任务使用了多少 RAM。通过有效利用上述策略,我们可以克服内存错误。


下一个主题Python 图形编程