Lassen Sie Python MemoryError auslösen, anstatt meinen gesamten Speicherplatz zu verbrauchen

7

Wenn ich ein Python-Programm mit einem Speicherverlust ausführe, würde ich normalerweise erwarten, dass das Programm irgendwann stirbt MemoryError. Stattdessen wird der gesamte virtuelle Speicher verwendet, bis auf meiner Festplatte nicht mehr genügend Speicherplatz vorhanden ist. Ich verwende Mac OS X 10.8 auf einem Retina-MacBook Pro. Mein Computer hat in der Regel zwischen 10 GB und 20 GB frei. Mac OS X ist intelligent genug, um nicht vollständig zu sterben, wenn auf der Festplatte nicht genügend Speicherplatz vorhanden ist (vielmehr wird ein Dialogfeld angezeigt, in dem ich das Beenden meiner GUI-Programme erzwingen kann).

Gibt es eine Möglichkeit, Python zum Sterben zu bringen, wenn der reale Speicher oder eine angemessene Menge virtuellen Speichers knapp wird? Soweit ich das beurteilen kann, passiert dies unter Linux. Ich denke, Mac OS X ist großzügiger als Linux mit virtuellem Speicher (die Tatsache, dass ich eine SSD habe, könnte ein Teil davon sein; ich weiß nicht, wie intelligent OS X mit diesem Zeug ist). Vielleicht gibt es eine Möglichkeit, den Mac OS X-Kernel anzuweisen, niemals so viel virtuellen Speicher zu verwenden, dass weniger als beispielsweise 5 GB auf der Festplatte frei sind?

asmeurer
quelle
"Vielleicht gibt es eine Möglichkeit, den Mac OS X-Kernel anzuweisen, niemals so viel virtuellen Speicher zu verwenden, dass weniger als beispielsweise 5 GB auf der Festplatte frei sind?" Ihr vorgeschlagener Fix würde nicht helfen. Wenn der Speicher früher knapp wird, tritt das Problem nur früher auf.
David Schwartz
Oh ja, du hast recht. Duh :) Ich denke, ich möchte, dass nur Python das macht, nicht das ganze System.
Asmeurer

Antworten:

9

Python Level

Laut diesem Beitrag ist resource.setrlimit () vielleicht das, was Sie brauchen.

Beispiel

#!/usr/bin/python

import resource
import sys
import signal
import time

import os

soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
print 'Soft limit starts as  :', soft

# Use env MY_PY_SET_LIMIT to control limit value
# If MY_PY_SET_LIMIT is not set, RLIMIT_STACK will not change
MY_PY_SET_LIMIT = os.getenv('MY_PY_SET_LIMIT')

if MY_PY_SET_LIMIT != None :
  resource.setrlimit(resource.RLIMIT_STACK, (int(MY_PY_SET_LIMIT), int(MY_PY_SET_LIMIT)))

soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
print 'Soft limit changed to :', soft

TMP = ""

for i in range(10240):
  TMP += "0123456789"
  print len(TMP)

System Level

Für Linux wird es tatsächlich mehrmals zuvor auf verschiedenen "Boards" von Stackexchange und anderen Sites beantwortet. Die beste Antwort, die ich gefunden habe, ist hier , die ein Beispiel enthält.

Die Antwort lautet ulimit -v <kByte> . Beispiel: Begrenzen der VM auf 10 MB:

ulimit -v 10240

Unter OS X gibt es jedoch Hinweise ( hier und hier ), dass ulimit möglicherweise ignoriert wird. Diese Links sind sehr alt. Ich bin nicht sicher, ob sich die Situation in neueren OS X-Versionen ändert.

Es gibt diesen Beitrag für OS X zur Verwendung von launchd conf. Es wird empfohlen, einen Stapelabschnitt in einer Plist-Konfiguration zu verwenden

<key>SoftResourceLimits</key>
<dict>
    <key>Stack</key>
    <integer>10000000000</integer>
</dict>

Oder mit /etc/launchd.conf

launchd.conf

umask 002
limit stack 67104768 67104768
limit maxproc 3400 4500
limit maxfiles 256 unlimited
setenv PATH /opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin

PS: Laut Mountain Lion man wird launchd.conf (5) pro Benutzer launchd.conf nicht unterstützt

 $HOME/.launchd.conf  Your launchd configuration file (currently unsupported).
John Siu
quelle
ulimitin der Tat scheint nicht zu funktionieren.
Asmeurer
das ließ uns keine andere Wahl, als mit launchd zu gehen
John Siu
Es ist nicht klar, wohin das führen soll. Es klingt vielleicht so, als ob es Teil einer info.plist in einem .app-Paket sein sollte, aber Python funktioniert so nicht.
Asmeurer
aktualisierte Antwort auf geklärt
John Siu
Update mit einer möglichen Python-Lösung.
John Siu