Python 如何处理内存错误
MemoryError表示Python解释器为我们的Python程序用尽了它的内存分配。这可能是由于Python环境的设置问题,也可能是程序本身一次获取了太多的东西。
什么是内存错误
Python内存错误,或者更简单地说,我们的RAM中用于程序执行的内存空间用完了。
这个问题很可能是由于把所有的数据加载到系统的内存中造成的。对于庞大的数据集,建议采用批量处理。与其将完整的数据放入内存,不如将其保留在硬盘上,分块检索。
内存错误表明我们的软件已经达到了它的内存极限。这标志着我们的软件生成的对象数量过多。在这种情况下,我们必须寻找我们程序中可能占用大量内存的区域。
当一个任务的存储空间耗尽时,就会发生内存错误。
内存错误的一个例子
让我们从一个高度贪婪的代码块开始,看看这个问题的作用。在下面的脚本中,我们从一个空列表开始,使用嵌套列表向其中添加 Python 字符串。在这种情况下,我们使用了三层嵌套列表,每层有一千次迭代。这表明在程序之后,列表中有 1,000,000,000 次的字符串 “More” 的重复。
代码
# Python program to write a greedy program that will run out of memory
# Initializing a list
s = []
# Starting a for loop
for i in range(1000):
# The second for loop
for j in range(1000):
# The third for loop
for k in range(1000):
# Adding the string to the list
s.append("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的安装是足够的,但这些问题仍然存在,可能有必要重新思考代码。可悲的是,除了分析和优化我们的代码外,没有简单的解决办法来消除这个问题。密切注意任何巨大的或嵌套的循环,以及每次我们将巨大的数据集一次性加载到我们的程序中,就像上面的例子。
在这些情况下,将工作分成几组通常是可取的,使拉姆在调用之间被释放。例如,在下面的程序中,我们将之前的嵌套循环分成了三个独立的循环,每个循环都运行了333,333,333次。这个程序仍然运行了100万次,但是因为我们可以通过垃圾收集工具清空内存,所以它不再抛出MemoryError。
请看下面的嵌套循环分批运行的例子
代码
# Python program to show how to do batching of a program and use a garbage collector to save memory
# importing the garbage collection module
import gc
# Initializing the lists
a = []
b = []
c = []
l = []
# Executing the first batch
for i in range(33333333):
a.append("More")
# Using the garbage collector
gc.collect()
# Repeating the above steps two more times
for j in range(33333333):
b.append("More")
gc.collect()
for k in range(33333333):
c.append("More")
gc.collect()
# Adding all batches to a final list
l.extend([a,b,c])
如何限制内存和CPU的使用
我们现在将看到如何限制运行中的程序对内存或CPU的使用,以防止内存错误。我们可以通过使用资源模块来完成这两项任务,如以下代码所示。
代码
# Python program to show how to use the resource module to put limits on the CPU and memory usage
# importing the required modules
import signal
import resource
import os
# Defining a function to check the time limit exceeding the case
def time_exceed(sig, fr):
print("The time limit is exceeded by the program")
raise SystemExit(1)
# Defining function to set the maximum time limit on the run time
def set_max_runtime(sec):
# Using the resource module to set the limit
s, h = resource.getrlimit(resource.RLIMIT_CPU)
resource.setrlimit(resource.RLIMIT_CPU, (sec, h))
signal.signal(signal.SIGXCPU, time_exceed)
# Using the set_max_runtime function to limit the run time of the below code section
set_max_runtime(15)
# This is an infinite while loop; it can go on forever
# Due to setting the runtime limit, it will only run for 20 milliseconds, and then it will show the time limit exceeded
while True:
pass
输出
The time limit is exceeded by the program
An exception has occurred; use %tb to see the full traceback.
SystemExit: 1
代码限制了整个地址空间以控制内存消耗。
代码
# Python program to show how to use the resource module to put limits on the memory usage
# importing the required modules
import resource
# Defining a function to set the maximum memory usage allowed
def limit_mem():
s, h = resource.getrlimit(resource.RLIMIT_AS)
# Limiting the maximum memory usage to one-third of the original
s /= 3
resource.setrlimit(resource.RLIMIT_AS, (s, h))
limit_mem()
# Using the try-except code blocks to catch the exception
try:
l=[]
for i in range(1000000):
l.append('a')
except MemoryError:
print("Memory limit is exceeded by the code")
输出
Memory limit is exceeded by the code
避免Python中的内存错误
程序产生内存错误的最常见原因是在处理巨大的数据集时。在处理机器学习项目时,我们经常遇到大数据集,当执行回归或聚类的机器学习算法时,会导致计算机内存立即耗尽。我们可以通过运行Generator函数来解决此类问题。在处理大型数据集时,它可以作为用户定义的方法来实现。
在不导入整个数据集的情况下,由于Python生成器函数的存在,我们可以很容易地将大数据集分成几块。在处理许多行数据的巨大项目时,生成器是令人难以置信的帮助。生成器的函数返回迭代器对象。数据可以使用这些迭代器对象进行循环。一个典型的迭代器方法是用Python循环写的,在整个数据集上进行迭代。这时生成器函数就派上用场了;它可以防止整个数据集的循环,因为这样做会导致内存错误,使应用程序崩溃。
Python 中的生成器函数与其它常规函数不同,它包含了一个叫做 yield 的关键字,代替了惯用的 return 关键字,后者通常会返回函数的结果。然而,一旦执行了 yield 命令,它就不会终止函数。
我们提供了一个实例生成器函数。
代码
# Python program to show how to use a generator function to iterate over large ranges without overflowing the ram
# Defining a generator function
def generator():
for i in range(10000000):
# The function will yield a natural number every time it is called
# It does not store the complete range in the memory all at once
yield i
# Calling the generator function
gen = generator()
# Calling the gen object to print the integer
for i in gen:
print(i)
使用关系型数据库
大型数据集可以使用关系型数据库进行存储和访问。
从根本上说,数据被保存在磁盘上,可以通过正常的查询语言访问,并逐渐分批加载(SQL)。
大多数(所有?)计算机语言和几个机器学习应用程序可以很容易地与关系数据库连接,作为一个开源的数据库解决方案,如MySQL或Postgres。此外,像SQLite这样的轻量级方法也是一种选择。
总结
我们已经用很大的篇幅介绍了Python编程语言的内存错误和处理名称错误的方法。关于内存错误,最重要的是要记住有多少RAM被用于任务。我们可以通过有效利用上述策略来超越内存错误。