Wenn Ruby fork
aufruft, erstellt das Betriebssystem eine Kopie des Adressraums der gesamten übergeordneten Prozesse, selbst wenn fork nur exec
aufgerufen wird, ein anderer kleiner Prozess wie ls
. Momentan muss Ihr System in der Lage sein, einen Teil des Speichers mit mindestens der Größe der Ruby-Parent-Orizisse zuzuweisen, bevor es auf den tatsächlichen Wert des untergeordneten Prozesses reduziert wird.
So Schienen ist im Allgemeinen ziemlich Speicher hungrig. Dann, wenn etwas fork
verwendet, benötigen Sie doppelt so viel Speicher.
TL; DR Verwenden Sie posix-spawn statt Gabel, wenn Sie die Kontrolle über den Code haben. Andernfalls wird Ihr VM 1024MB oder ein bisschen mehr Swap-Speicher geben, um die Flaute für die fork
Anruf zu nehmen
Beispiel Ruby-Speichernutzung mit fork
Nehmen Sie eine zufällige VM, hat dieser ein Swap-Speicher deaktiviert ist:
$ free -m
total used free shared buffers cached
Mem: 1009 571 438 0 1 35
-/+ buffers/cache: 534 475
Swap: 0 0 0
Blick auf die Mem:
Zeile und Spalte free
. Dies ist um über Ihre Größenbeschränkung für einen neuen Prozess, in meinem Fall 438
MiB
Mein buffers/cached
wurden bereits flushed für diesen Test, so dass mein free
Speicher ist es Grenze. Möglicherweise müssen Sie die Werte buffers/cache
berücksichtigen, wenn sie groß sind. Linux hat die Fähigkeit, veralteten Cache zu verwerfen, wenn Speicher von einem Prozess benötigt wird.
Verwenden Sie einige Speicher
erstellen Ruby-Prozess mit einer Schnur um die Größe des freien Speichers auf. Es gibt einige Overhead für den ruby
Prozess, so dass es nicht genau free
entsprechen wird.
$ ruby -e 'mb = 380; a="z"*mb*2**20; puts "=)"'
=)
Dann wird die Saite machen etwas größer:
$ ruby -e 'mb = 385; a="z"*mb*2**20; puts "=)"'
-e:1:in `*': failed to allocate memory (NoMemoryError)
from -e:1:in `<main>'
eine fork
zum Ruby-Prozess hinzufügen, reduziert mb
, bis es läuft.
$ ruby -e 'mb = 195; a="z"*mb*2**20; fork; puts "=)"'
=)
Ein etwas größeres Gabel Prozess wird die ENOMEM
Fehler erzeugen:
$ ruby -e 'mb = 200; a="z"*mb*2**20; fork; puts "=)"'
-e:1:in `fork': Cannot allocate memory - fork(2) (Errno::ENOMEM)
from -e:1:in `<main>'
einen Befehl mit Backticks Rennen startet das Verfahren mit einem fork
so das gleiche Ergebnis hat:
$ ruby -e 'mb = 200; a="z"*mb*2**20; `ls`'
-e:1:in ``': Cannot allocate memory - ls (Errno::ENOMEM)
from -e:1:in `<main>'
Also los geht's, du brauchst etwa doppelt so viel wie der Elternprozessspeicher in der Lage, einen neuen Prozess zu starten. MRI Ruby basiert stark auf fork
für sein Multi-Prozess-Modell, dies liegt am Design von Ruby, das eine global interpreter lock (GIL) verwendet, die nur einen Thread pro Rubin-Prozess gleichzeitig ausführen lässt.
Ich glaube, Python hat viel weniger Verwendung von fork
intern. Wenn Sie os.fork
in Python zu tun verwenden, tritt das gleiche aber:
python -c 'a="c"*420*2**20;'
python -c 'import os; a="c"*200*2**20; os.fork()'
Oracle eine detailed article on the problem haben und über die Verwendung der Alternative von posix_spawn()
zu sprechen. Der Artikel richtet sich an Solaris, aber dies ist ein allgemeines POSIX-Unix-Problem, das gilt für Linux (wenn nicht die meisten Unices).
Es gibt auch eine Ruby-Implementierung von posix-spawn
, die Sie verwenden könnten, wenn Sie die Kontrolle über den Code haben. Dieses Modul ersetzt nichts in Rails, daher wird es Ihnen hier nicht weiterhelfen, wenn Sie die Aufrufe von fork
nicht selbst ersetzen.
Es ist schwer zu sagen, ob Sie mehr RAM benötigen. Im Allgemeinen kann eine mittelgroße Rails-App 512M verwenden. Rails lädt die gesamte Anwendung in den Speicher x, aber viele Server/Prozesse, die Sie verwenden. Ich setze RAM generell auf 2GB, um es überhaupt zu versuchen. Ich mache meinen Entwickler im Allgemeinen, aber keine virtuelle Box. –