Orien ma rację, jest to wywołanie systemowe fork () wywołane przez ProcessBuilder lub Runtime.exec lub inne środki JVM wykonujące proces zewnętrzny (np. Inną uruchomioną mrówkę JVM, komendę git itp.).
Na listach mailowych Jenkinsa pojawiło się kilka postów na ten temat: Nie można uruchomić programu „git” ... błąd = 12, Nie można przydzielić pamięci
Jest ładny opis problemu na liście deweloperów SCons : fork () + exec () vs posix_spawn ()
Od dawna istnieje raport o błędach JVM z rozwiązaniami: Użyj posix_spawn, a nie fork, na S10, aby uniknąć wyczerpania wymiany . Ale nie jestem pewien, czy to rzeczywiście trafiło do JDK7, jak sugerują komentarze.
Podsumowując, w systemach uniksowych, gdy jeden proces (np. JVM) musi uruchomić inny proces (np. Git), wywoływane jest systemowe wywołanie, fork()
które skutecznie powiela bieżący proces i całą jego pamięć (Linux i inni optymalizują to za pomocą kopiowania -on-write, więc pamięć nie jest kopiowana, dopóki dziecko nie spróbuje do niej napisać). Duplikat następnie wykonuje kolejne wywołanie systemowe, exec()
aby uruchomić inny proces (np. Git), w którym to momencie cała ta skopiowana pamięć z procesu nadrzędnego może zostać odrzucona przez system operacyjny. Jeśli proces nadrzędny używa dużej ilości pamięci (jak to zwykle robią procesy JVM), wywołanie fork()
może się nie powieść, jeśli system operacyjny stwierdzi, że nie ma wystarczającej ilości pamięci + wymiany do przechowywania dwóch kopii, nawet jeśli proces potomny nigdy tak naprawdę nie będzie użyj tej skopiowanej pamięci.
Istnieje kilka rozwiązań:
Dodaj więcej pamięci fizycznej / RAM do urządzenia.
Dodaj więcej przestrzeni wymiany, aby nakłonić ją fork()
do działania, nawet jeśli przestrzeń wymiany nie jest absolutnie potrzebna do niczego. To jest rozwiązanie, które wybrałem, ponieważ dość łatwo jest dodać plik wymiany, a ja nie chciałem żyć z potencjalną śmiercią procesów z powodu nadmiernego zaangażowania.
W systemie Linux włącz overcommit_memory
opcję systemu vm ( / proc / sys / vm / overcommit_memory ). W przypadku nadmiernego zaangażowania wezwanie do fork()
zawsze kończy się powodzeniem, a ponieważ proces potomny tak naprawdę nie będzie używał tej kopii pamięci, wszystko jest w porządku. Oczywiście możliwe jest, że przy nadmiernym zaangażowaniu twoje procesy będą próbowały zużywać więcej pamięci niż jest dostępne i zostaną zabite przez jądro. To, czy jest to właściwe, zależy od innych zastosowań urządzenia. Maszyny o znaczeniu krytycznym prawdopodobnie nie powinny ryzykować amokera z brakiem pamięci. Jednak wewnętrzny serwer programistyczny, który może pozwolić sobie na pewne przestoje, byłby dobrym miejscem na włączenie funkcji overcommit.
Zmień JVM, aby nie używała fork()
+, exec()
ale używa, posix_spawn()
gdy jest dostępna. Jest to rozwiązanie wymagane w powyższym raporcie o błędach JVM i wymienione na liście mailingowej SCons. Jest także zaimplementowany w java_posix_spawn .
Próbuję dowiedzieć się, czy ta poprawka trafiła do JDK7. Jeśli nie, zastanawiam się, czy ludzie z Jenkins byliby zainteresowani obejściem, takim jak java_posix_spawn. Wydaje się, że próbowano zintegrować to z Apache commons-exec .
Programmieraffe, nie jestem w 100% pewien, ale twój link sugeruje, że poprawka znajduje się w JDK7 i JDK6 1.6.0_23 i nowszych. Dla przypomnienia uruchomiłem OpenJDK 1.6.0_18.
Zobacz /programming/1124771/how-to-solve-java-io-ioexception-error-12-cannot-allocate-memory-calling-run