Python无法捕获MemoryError异常

19

我用try/except包装了一些可能会耗尽内存的代码。然而,虽然会生成MemoryError,但却没有被捕获。

我有下面这段代码:

    while True:
        try:
            self.create_indexed_vocab( vocab )
            self.reset_weights()
            break;
        except MemoryError:
            # Stuff to reduce size of vocabulary
            self.vocab, self.index2word = None, None
            self.syn0, self.syn1 = None, None

            self.min_count += 1
            logger.info( ...format string here... )

我得到了以下的Traceback:

File "./make_model_tagged_wmt11.py", line 39, in <module>
  model.build_vocab(sentences)
File "/root/CustomCompiledSoftware/gensim/gensim/models/word2vec.py", line 236, in build_vocab
  self.reset_weights()
File "/root/CustomCompiledSoftware/gensim/gensim/models/word2vec.py", line 347, in reset_weights
  self.syn0 += (random.rand(len(self.vocab), self.layer1_size) - 0.5) / self.layer1_size
File "mtrand.pyx", line 1044, in mtrand.RandomState.rand (numpy/random/mtrand/mtrand.c:6523)
File "mtrand.pyx", line 760, in mtrand.RandomState.random_sample (numpy/random/mtrand/mtrand.c:5713)
File "mtrand.pyx", line 137, in mtrand.cont0_array (numpy/random/mtrand/mtrand.c:1300)
MemoryError

我正在Ubuntu 12.04上运行Python 2.7.3。

reset_weights 行中的 self.syn0 正是我预计会引发异常的地方(它分配了一个大数组)。令人困惑的是,我无法捕获内存错误并执行可以使数组大小变小的操作。

是否存在特殊情况导致无法捕获 MemoryError


2
你确定那些是抛出异常的代码行吗?尝试将 except 行改为 except: 并在其中打印一些内容,以确保这些是正确的代码行。 - idanshmu
1
@DannyElly,看起来堆栈跟踪显示了对reset_weights()的调用,这是except之前的最后一行。我预计reset_weights正在被调用。 - apg
2
@Eponymous,你在调用create_indexed_vocab函数时的参数vocab是否应该改为self.vocab?另外,针对@DannyElly的建议,或许在create_indexed_vocab函数中还有一个隐含的reset_weights函数调用?但由于此处报告了MemoryError错误,这可能并不重要... - apg
2
@Eponymous 我仍然会更改except行并在那里打印一些东西。往往,我们确信我们正在调试正确的代码块,而实际上问题却出现在另一个代码块中。这可能非常令人沮丧。当我遇到这样的错误时,我会尽可能添加更多的打印语句,以确保我正在处理正确的问题。 - idanshmu
1
@Eponymous 你确定try块中的代码会抛出异常吗?你是否在怀疑的代码行(self.reset_weights())之前和之后打印过信息,只看到了之前的打印?这是我能帮助你的最好方法。我知道我提供的建议可能很琐碎和愚蠢,但我们都是人,有时候会忽略显而易见的事情。祝你好运! - idanshmu
显示剩余2条评论
1个回答

19
由于底层内存管理架构(C的malloc()函数)的原因,解释器可能无法完全从这种情况中恢复;尽管如此,它仍会引发异常,以便在运行失控程序为原因时打印堆栈跟踪。
(请参见文档
通常情况下,您仍然可以捕获MemoryErrors。不知道当抛出MemoryError时会发生什么,我猜测当情况变得非常糟糕且没有足够的内存来处理时,可能无法捕获它。
此外,由于您可能无法真正从中恢复(请参见上文),因此捕获它可能并没有太多意义。 您应该通过例如只允许列表具有有限大小来避免耗尽内存并限制程序使用的内存量。

1
文档中的提示是我写这个问题的原因。我想知道不可捕获的异常是否真的会发生(以及它是否可能在我的特定情况下发生),或者我的 Python 技能是否太低,我是否错过了语言细微差别。 - Eponymous
5
RAM是共享资源,因此避免内存耗尽是不可能的。即使在MS-Windows上有resource模块可用以检查内存,但在你检查可用内存并分配它之间,其他进程可能会占用你想要使用的一些内存。因此,一个想要使用尽可能多RAM的程序的内存分配循环应该是 while(allocation fails): adjust requirements; allocate。在Python中,我所知道的唯一检测失败分配的方法是MemoryError - Eponymous
我放弃了,所以我会把被接受的答案给你。(因为你是唯一的回答。) - Eponymous
仅通过限制列表的大小来实现,例如仅允许列表具有有限的大小。但是,这个大小应该是多少呢?使用大块内存可以加快计算速度。在Python中,我们如何找到正确的平衡点,考虑到内存因机器和时间而异? - endolith
@Eponymous 我知道你很多年前发表了你的评论,可能已经了解到内存耗尽是可能的。系统在存储容量和用户/系统进程可用存储容量方面都有物理限制。否则,你可以编写一个程序,先填满RAM,然后填满持久存储,最后导致系统可能永久损坏而崩溃。即使在2023年,超过虚拟内存也是可能的,系统配置将导致进程终止或操作系统崩溃。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接