Orien ist korrekt, es ist der Systemaufruf fork (), der von ProcessBuilder oder Runtime.exec oder anderen Mitteln der JVM ausgelöst wird, die einen externen Prozess ausführen (z. B. eine andere JVM, auf der ant ausgeführt wird, ein git-Befehl usw.).
Es gab einige Beiträge in den Jenkins-Mailinglisten zu diesem Thema: Programm "git" kann nicht ausgeführt werden ... error = 12, Speicher kann nicht zugeordnet werden
Es gibt eine schöne Beschreibung des Problems auf der SCons- Entwicklerliste : fork () + exec () vs posix_spawn ()
Es gibt einen langjährigen JVM-Fehlerbericht mit Lösungen: Verwenden Sie posix_spawn, nicht fork, auf S10, um eine Erschöpfung des Swaps zu vermeiden . Aber ich bin mir nicht sicher, ob dies tatsächlich in JDK7 geschafft hat, wie aus den Kommentaren hervorgeht.
Zusammenfassend lässt sich sagen, dass auf Unix-ähnlichen Systemen, wenn ein Prozess (z. B. die JVM) einen anderen Prozess (z. B. git) starten muss, ein Systemaufruf ausgeführt wird, fork()
der den aktuellen Prozess und seinen gesamten Speicher effektiv dupliziert (Linux und andere optimieren dies durch Kopieren) -on-write, damit der Speicher erst kopiert wird, wenn das Kind versucht, darauf zu schreiben). Der doppelte Prozess führt dann einen weiteren Systemaufruf durch, exec()
um den anderen Prozess (z. B. git) zu starten. An diesem Punkt kann der gesamte vom übergeordneten Prozess kopierte Speicher vom Betriebssystem verworfen werden. Wenn der übergeordnete Prozess viel Speicher verwendet (wie dies bei JVM-Prozessen fork()
der Fall ist ), schlägt der Aufruf möglicherweise fehl, wenn das Betriebssystem feststellt, dass nicht genügend Speicher + Swap für zwei Kopien vorhanden ist, auch wenn der untergeordnete Prozess dies tatsächlich nie tun wird Verwenden Sie diesen kopierten Speicher.
Es gibt verschiedene Lösungen:
Fügen Sie dem Computer mehr physischen Speicher / RAM hinzu.
Fügen Sie mehr Swap-Speicherplatz hinzu, um das fork()
Arbeiten zu erleichtern, obwohl der Swap-Speicherplatz für nichts unbedingt benötigt wird. Dies ist die Lösung, die ich gewählt habe, weil es ziemlich einfach ist, eine Swap-Datei hinzuzufügen, und ich wollte nicht mit dem Potenzial leben, dass Prozesse aufgrund von Überbindung abgebrochen werden.
Aktivieren Sie unter Linux die overcommit_memory
Option des VM-Systems ( / proc / sys / vm / overcommit_memory ). Mit Overcommit fork()
würde der Aufruf von immer erfolgreich sein, und da der untergeordnete Prozess diese Kopie des Speichers nicht wirklich verwenden wird, ist alles in Ordnung. Natürlich ist es möglich, dass Ihre Prozesse bei Overcommit tatsächlich versuchen, mehr Speicher als verfügbar zu verwenden, und vom Kernel beendet werden. Ob dies angemessen ist, hängt von den anderen Verwendungszwecken der Maschine ab. Missionskritische Maschinen sollten wahrscheinlich nicht riskieren, dass der Killer mit zu wenig Speicher Amok läuft. Ein interner Entwicklungsserver, der sich Ausfallzeiten leisten kann, ist jedoch ein guter Ort, um eine Überbindung zu ermöglichen.
Ändern Sie die JVM so, dass sie nicht fork()
+ verwendet, exec()
sondern verwendet wird, posix_spawn()
wenn verfügbar. Dies ist die Lösung, die im obigen JVM-Fehlerbericht angefordert und in der SCons-Mailingliste aufgeführt ist. Es ist auch in java_posix_spawn implementiert .
Ich versuche herauszufinden, ob dieses Update es in JDK7 geschafft hat. Wenn nicht, frage ich mich, ob die Jenkins-Leute an einer Arbeit wie java_posix_spawn interessiert wären. Es scheint Versuche gegeben zu haben, dies in Apache commons-exec zu integrieren .
Programmieraffe, ich bin nicht 100% sicher, aber Ihr Link deutet darauf hin, dass das Update in JDK7 und JDK6 1.6.0_23 und höher enthalten ist. Für die Aufzeichnung habe ich OpenJDK 1.6.0_18 ausgeführt.
Siehe /programming/1124771/how-to-solve-java-io-ioexception-error-12-cannot-allocate-memory-calling-run