Wie kann ich die für einen Prozess verfügbare Speichermenge begrenzen?

11

Ich entwickle ein Programm in go; Gelegentlich werden sehr große Speichermengen zugewiesen (>> 10 GB auf einem Computer mit 8 GB physischem Speicher), wodurch das System nicht mehr reagiert. Ich möchte die Menge an Speicher begrenzen, die der Prozess zuweisen kann. Die übliche Art, wie ich das machen würde, ist:

ulimit -m 4000000 ; ./myprogram

... was mein Programm beenden sollte, wenn es versucht, mehr als 4 GB Speicher zu verwenden.

Unter OS X El Capitan scheint dies keine Auswirkungen zu haben. Selbst ulimit -m 1(Beschränkung aller Programme auf nur 1 KB Speicher!) ist unwirksam.

Wie kann ich eine Obergrenze für den für einen bestimmten Prozess verfügbaren Speicher festlegen?

cpcallen
quelle
Was meinst du, wenn du sagst, wie ich das normalerweise machen würde ? Genauer gesagt, wann machst du das normalerweise? Und wenn Sie es tun, meinen Sie das unter Mac OS X El Capitan oder in einer anderen Umgebung? Können Sie ein Beispiel geben, wann Sie es erfolgreich eingesetzt haben? Grundsätzlich versuche ich nur zu klären, ob dieser Prozess für Sie normal funktioniert, aber für dieses spezielle Programm nicht funktioniert. Oder funktioniert es bei Ihnen überhaupt nicht, aber Sie denken, es sollte?
Monomeeth
1
Mit "der üblichen Art, wie ich das machen würde" meine ich die Art und Weise, wie ich das mit anderen Unix-Varianten machen würde. Ich ulimit -mstelle fest, dass ich gerade festgestellt habe, dass es unter Linux nicht mehr funktioniert (> 2.4.30), ulimit -vaber immer noch wie erwartet funktioniert. (Wie ulimit -m, ulimit -vscheint auch keine Auswirkung auf OS X zu haben.)
cpcallen
Das klingt so, als hätten Sie einen Speicherverlust in dem Programm, das Sie schreiben, und müssen eine bessere Speicherbereinigung durchführen. Haben Sie sich über die Speicherverwaltung in go informiert?
Todd Dabney
1
Nein, kein Speicherverlust - nur eine Diagrammsuche in einem möglicherweise sehr großen Zustandsraum. Ich könnte Code hinzufügen, um die Suche abzubrechen, wenn die verschiedenen internen Strukturen zu groß werden, aber ich hatte erwartet, dass ich mit einem Shell-Einzeiler dasselbe tun kann (um zu verhindern, dass die Maschine durch große Eingaben eingeklemmt wird).
cpcallen

Antworten:

1

Es gibt zwei Ansätze, um die Speichernutzung einzuschränken: Ex post facto und präventiv. Das heißt, Sie können versuchen, Ihr Programm zu beenden, nachdem es zu groß geworden ist, oder Sie können es so programmieren, dass es überhaupt nicht zu groß wird.

Wenn Sie auf dem Ex-post-Facto-Ansatz bestehen, können Sie das folgende Bash-Skript verwenden. Dieses Skript ermittelt zuerst die Speichermenge (wie durch "resident set size" definiert), die der Prozess mit processid pid verwendet, filtert alle nicht numerischen Daten mit grep heraus und speichert die Menge als Variable n. Das Skript prüft dann, ob n größer als das angegebene x ist. Wenn dies der Fall ist, wird der Prozess mit processid pid abgebrochen.

Bitte beachten Sie:

  1. Sie müssen durch <pid>die Prozess-ID Ihres Programms ersetzen .
  2. Sie müssen durch <x>rss = "resident set size" (dh die tatsächliche Speichergröße) ersetzen, die das Programm nicht überschreiten soll.

n=$(ps -<pid> -o rss | grep '[0-9]') if [ $n -gt <x> ]; then kill -9 <pid>; fi

Wenn Sie möchten, dass dies alle y Sekunden ausgeführt wird, schließen Sie es einfach in eine Schleife ein und weisen Sie es an, nach jeder Iteration y Sekunden zu warten. Sie können auch einen ähnlichen Befehl mit schreiben top. Ihr Ausgangspunkt wäre top -l 1|grep "<pid>"|awk '{print $10}'.

Die Antwort von @ kenorb hat mir bei meinem Skript geholfen


Während ich glaube, dass dies die Frage beantwortet, glaube ich, dass es auf lange Sicht besser ist, einen präventiven Ansatz mit manueller Speicherzuweisung zu wählen.

Sind Sie sicher, dass die Speichernutzung wirklich ein Problem ist? In der Go- Dokumentation heißt es:

Der Go-Speicherzuweiser reserviert einen großen Bereich des virtuellen Speichers als Arena für Zuweisungen. Dieser virtuelle Speicher ist lokal für den jeweiligen Go-Prozess. Die Reservierung beraubt andere Speicherprozesse nicht.

Wenn Sie immer noch glauben, dass Sie ein Problem haben, empfehle ich Ihnen, Ihren Speicher manuell zu verwalten, wie dies in der Programmiersprache C erfolgt. Da go in C geschrieben ist, habe ich vermutet, dass es Möglichkeiten gibt, in die C-Speicherverwaltung / -zuordnungen zu gelangen, und tatsächlich gibt es diese. Sehen Sie sich dieses Github- Repository an, das

Ermöglicht die manuelle Speicherverwaltung über den Standard-C-Allokator für Ihr System. Es ist eine dünne Hülle auf Malloc, Calloc und frei von. Weitere Informationen zu diesen Funktionen für Ihr System finden Sie unter man malloc. Diese Bibliothek verwendet cgo.

Der Anwendungsfall lautet wie folgt:

Warum willst du das?

Wenn ein Programm Speicherdruck verursacht oder dem System der Speicher ausgeht, kann es hilfreich sein, die Speicherzuweisungen und Freigaben manuell zu steuern. Go kann Ihnen bei der Steuerung von Zuordnungen helfen, es ist jedoch nicht möglich, nicht benötigte Daten explizit freizugeben.

Dies scheint eine bessere langfristige Lösung zu sein.

Wenn Sie mehr über C erfahren möchten (einschließlich Speicherverwaltung), ist die Programmiersprache C die Standardreferenz.

Evan Rosica
quelle
Ich bin sicher, dass die Speichernutzung wirklich ein Problem ist. Als das Programm unerwartet auf> 2x physische Speichergröße angewachsen war, reagierte der Computer aufgrund von Seitenüberschreitungen fast nicht mehr. Es dauerte ungefähr eine Stunde zwischen dem Drücken von ^ C und dem erneuten Reagieren von macOS auf Mausklicks. In der Zwischenzeit war der einzige Beweis dafür, dass es nicht eingefroren war, das leise Geräusch der Festplatte, die schnell tickte.
cpcallen
Dies ist in der Praxis wahrscheinlich eine vernünftige Lösung, aber im Gegensatz zu ulimit auf (Nicht-Darwin-) UNIX-Betriebssystemen hängt es davon ab, dass genügend Speicher rechtzeitig zugewiesen werden kann, um den Befehl kill erfolgreich auszuführen. Ich hätte wirklich lieber Prozessgrößenbeschränkungen, die vom Kernel erzwungen werden.
cpcallen
@cpcallen führt einige Suchvorgänge durch. Es scheint, dass der Parameter "-m to ulimit" keine Auswirkungen auf Linux-Systeme mit Kernelversionen hat, die aktueller als 2.4.30 sind. Es scheint, dass OSX diese Änderung ebenfalls aufgegriffen hat. Versuchen Sie die Option -v, um den Adressraum zu begrenzen
Evan Rosica