何时在Python中捕获MemoryError?
我在尝试理解在Python中什么时候捕获MemoryError
是有意义的,我想到了两个场景:
场景1:成功捕获了MemoryError。
import numpy as np
try:
a = np.ones(100000000000)
except MemoryError:
print 'got memory error, plan B'
a = np.ones(10) # this gets created
场景2:我的程序卡住了。
silly = []
c = 0
try:
while True:
silly.append((str(c))) # just increasing the list
c += 1
if c % 1000000 == 0:
print 'counter : {}'.format(c)
except MemoryError:
print 'oops' # never get here
silly.append('silly')
我的猜测是,在第一个情况下,Python“知道”需要分配多少内存,因此会抛出MemoryError
异常。而在第二种情况下,Python并不知道我想要的silly
有多大。不过,list
是一个动态数组;所以,Python应该知道扩展这个数组到一定大小会导致MemoryError
,那为什么没有抛出异常呢?
我查看了这个问题,相关文档中的一段话是:
异常 MemoryError
当一个操作耗尽内存时抛出,但情况仍然可以通过删除一些对象来挽救。相关的值是一个字符串,指示哪种(内部)操作耗尽了内存。请注意,由于底层内存管理架构(C的malloc()函数),解释器可能并不总是能够完全从这种情况中恢复;尽管如此,它仍然会抛出一个异常,以便在程序失控时可以打印出堆栈回溯。
虽然这对我有帮助,但我仍然不太清楚发生了什么,而且我没有得到文档中提到的异常。
我的问题是:我在场景1中的猜测正确吗?为什么在场景2中没有抛出MemoryException
?
我使用的是Python 2.7.5+,操作系统是ubuntu 13.10。
2 个回答
在Python中,列表其实是一种链表,所以只有当系统无法分配更多内存时,才会出现内存异常MemoryError
。
这种情况通常发生在你的RAM(主内存)
使用到极限的时候。大多数操作系统会通过把优先级较低的数据移动到硬盘
来处理这种情况,因此在新的操作系统中你不太会遇到MemoryError
。不过,最好还是要注意这个问题,因为旧的操作系统没有这种机制,所以程序员需要自己处理。
MemoryError
是操作系统(OS)引发的,而不是Python本身引起的。
老旧的操作系统在发现内存满了的时候,会立刻抛出MemoryError。而大多数现代操作系统会尝试把内容移动到硬盘,当它发现主内存满了,没有空间来处理新的请求。如果在硬盘分配的空间里仍然无法容纳,或者当前请求的大小超过了为这个特定进程在RAM(主内存)中分配的数据存储空间的限制,那么就会抛出MemoryError。
你可以通过try exception
在你的Python程序中捕获由OS
引发的MemoryError
。
当你请求的内存超过了用于存储数据的Main Memory
的限制时,MemoryError
也会被OS
引发。
举个例子:如果你使用的是512MB的RAM,而你的操作系统在RAM中为数据分配了200MB,其余的用于代码。在这200MB中,操作系统为你的进程分配了50MB的数据空间,如果你请求存储100MB的数据,这就超过了限制,因此在这种情况下,操作系统也会抛出MemoryError。