2015-10-15 45 views
1

昨天又解決了Project Euler我管理bigfor i in range(n)週期陷入困境。Python:MemoryError vs OverflowError vs instant-system-freeze

我觀察到python拋出我不同的錯誤,取決於如何爲大的x變量

下面是一個mcve例如:

for i in range(x): 
    pass 

其中:

  • 如果x = 10**20我得到了一個OverflowError, 正是:OverflowError: range() result has too many items

  • 否則,如果x = 10**15我有一個MemoryError

  • 否則,如果x = 10**9我得到了一個instant-system-freeze,我必須硬重置我的電腦。很少,而不是凍結,我的電腦填滿大約5GB的交換,變得非常緩慢。

我試圖理解蟒built-in exception的含義:

  • OverflowError

    當算術運算的結果是太大而不能表示觸發。這不能長整數發生[...],並與普通整數,它會返回一個長整型,而不是大多數操作。 [...]

    這意味着整數不應拋出此異常;這個異常的原因是range()有太多的項目,所以我想這也10**15將拋出同樣的異常,但我得到了一個不同的...

  • MemoryError

    時引發的操作內存用完,但情況仍可能獲救(刪除某些對象)。 [...]

    哪些對象應該我刪除搶救這種情況呢?它只是退出,這樣的情況不能被救出......

    如果它感覺有太多ram使用,爲什麼凍結我的電腦用10**9


最後,我的問題是:

爲什麼我得到3種不同的結果,只有依賴於存儲在x變量的值?


注意

  • 我知道xrange的存在,有沒有這個問題,但我的問題是關於range
  • 我認爲用於拋出異常的值可能會改變,這取決於您的硬件。
  • 我的Python版本:2.7.6

回答

2

好,range試圖建立一個整個列表與儘可能多的項目x

對於瞬間掉線的情況,可以估計,假設64位和固定的8字節整數,x = 10**9約值8 Go。所以如果你沒有更多的(考慮到已經使用過的RAM),你可以看到系統交換的原因。

繼續往下看,如果函數不能分配足夠大的塊來保存結果(在10**15的情況下似乎相當大),則可能會產生MemoryError

我不知道range實施細節,但它可能會使用OverflowError確保元素的絕對最大數量(也許在某種程度上防止MemoryError,根據實際可用內存)。
如由@ShadowRanger註釋所提到的,OverflowError如果結果的長度不能放入一個size_t變量(2**31(32位)或2**63(64位)),因爲它不能初始化這樣的列表被擡起。

正如您所提到的,xrange沒有這個問題,因爲它不會生成整個列表,但每次迭代時都會生成一個值。爲什麼迭代器/生成器具有高效的內存。


所以我剛剛看了一下,就可以看到in the 2.7 source爲什麼它拋出一個OverflowError

+0

「OverflowError」是因爲CPython使用有符號的size_t來表示序列的長度;它甚至不可能初始化一個具有「2 ** 31」(32位)或「2 ** 63」(64位)或更多元素的「列表」,因爲存儲元素數量的變量不能代表一個很大的數字。 – ShadowRanger

+0

@ShadowRanger是的,你說得對。我有一段時間沒有使用輸入語言,所以我開始忘記基本的...... = o – Gall

0

range(x)將首先創建一個大小爲x的列表,然後用整數填充它。的影響是:

  • x = 10**20OverflowError,因爲一個列表只能容納sys.maxsize(通常爲32位2**31 - 12**63 - 1位和64位分別構建)的項目。
  • x = 10**15MemoryError,因爲內存不足以分配大小爲x的(未初始化的)列表。
  • x = 10**9:將創建一個大小爲x的列表;然後爲整數i < x,一個新的int對象將被創建並寫入磁盤;每個都需要內存分配。 (最終可能會導致MemoryError或不會導致MemoryError)。這會對CPU和內存造成很大的負擔,進而降低您的機器性能。

總之,對於前兩種情況,python很明顯無法完成任務,並且會引發異常。在第三種情況下,它認爲它可能能夠完成任務,儘管緩慢。

相關問題