Jenkins CI - Nie można przydzielić pamięci

9

Z powodzeniem przetestowałem jenkins-ci na Ubuntu 10.4 (z vmware fusion) na moim komputerze lokalnym. Teraz chcę zainstalować i używać go na moim serwerze wirtualnym w hosteurope. Podstawowa instalacja nie stanowiła problemu, ale teraz mam problemy z moim projektem kompilacji.

Po pobraniu aktualizacji rtęciowej z repozytorium mrówka jest wywoływana i zgłasza następujący błąd w moim projekcie kompilacji:

„Plik kompilacji: /var/lib/jenkins/workspace/concrete5-seed-clean/build.xml [właściwość] java.io.IOException: Nie można uruchomić programu” / usr / bin / env ”: java.io.IOException: error = 12, Nie można przydzielić pamięci ”

Znany jest problem z wielkością sterty na serwerach wirtualnych w hosteurope ( http://faq.hosteurope.de/index.php?cpid=13918 ), więc próbowałem ustawić rozmiar sterty ręcznie:

# for ant
export ANT_OPTS="-Xms512m -Xmx512m"

# jenkins
# edited /etc/default/jenkins, added line 
JAVA_ARGS="-Xms512m -Xmx512m"
# restarted jenkins via /etc/init.d/jenkins restart 

Po ustawieniu tej wartości dla mrówki uruchamiane jest polecenie „ant -diagnostics” i nie powoduje ono błędu, ale błąd nadal występuje, gdy próbuję zbudować projekt.

Dane serwera: - http://www.hosteurope.de/produkt/Virtual-Server-Linux-L

  • Ubuntu 10.4 LTS
  • RAM: 1 GB / dynamiczny 2 GB

Moje pytania: - Czy 1 GB wystarczy dla Jenkinsa, czy muszę zaktualizować serwer? - Czy ten błąd jest spowodowany przez mrówkę lub Jenkinsa?

Aktualizacja: Mam go uruchomioną z opcjami ant -Xmx128m -Xms128m, ale czasami błąd pojawia się ponownie. (to mnie przeraża, bo nie mogę go teraz odtworzyć: /)

Pomoc bardzo ceniona!

Pozdrawiam, Matthias

Programmieraffe
źródło
Rozwiązałem to przez ustawienie plików konfiguracyjnych Jenkins: JENKINS_JAVA_OPTIONS = "- Djava.awt.headless = true -Xms500m -Xmx1000m"
herbertD

Odpowiedzi:

10

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_memoryopcję 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

Patrick
źródło
Dzięki za szczegółową odpowiedź! W powiązanym poście Alf Høgemark mówi, że jest to teraz naprawione: ( stackoverflow.com/a/9127548/809939 ) Czy ktoś może to potwierdzić? Spróbuję również zaktualizować moją wersję Java.
Programmieraffe
Dodatkowe pytanie: co byś zaproponował? Overcommit-Memory-Setting? Pozdrawiam, Matthias
Programmieraffe
1
Dodanie pliku wymiany jest łatwe i proste. Ubuntu 12.04 (choć powinno być ono stosowane w dużej mierze na Linuksa w ogóle), artykuł ten był martwy prosta: digitalocean.com/community/articles/...
davemyron
1

Zwróć uwagę na komunikat wyjątku: Cannot run program "/usr/bin/env": java.io.IOException: error=12, Cannot allocate memory"Proces Java próbuje rozwidlić nowy proces, aby uruchomić polecenie, /usr/bin/envale w systemie operacyjnym zabrakło zasobów pamięci, aby utworzyć nowy proces. Nie jest to to samo, co w maszynie wirtualnej Java, której kończy się pamięć, więc żadne poprawki związane z flagami -Xmx nie naprawią tego. Będziesz musiał monitorować zasoby pamięci podczas uruchamiania kompilacji. Zwiększenie przestrzeni wymiany prawdopodobnie rozwiąże problem.

orien
źródło
To wirtualna maszyna Java (jeden ze stosów lub stosów), która nie ma pamięci, a NIE system komputerowy hosta.
mdpc,
Przepraszam za zwięzłość mojej oryginalnej odpowiedzi. Zaktualizowałem go, aby opisać, dlaczego w JVM brakuje pamięci.
orien
0

Prawdopodobnie ANT_OPTS zostały zastąpione przez Jenkinsa. Możesz także ustawić opcje bezpośrednio w pliku kompilacji, abyś mógł kontrolować przydział pamięci niezależnie od środowiska (shell, Jenkins, ...). W twoim pliku kompilacji (przykład:

<java fork="true" classname="..." >
    <jvmarg line="-Xms512M -Xmx512M" />
Matteo
źródło