2011-12-05 9 views
6

Występuje dziwny problem z Javą ProcessBuilder. Kod jest przedstawiony poniżej (w nieco uproszczonej formie)java.io.IOException: error = 11

public class Whatever implements Runnable 
{ 

public void run(){ 
     //someIdentifier is a randomly generated string 
     String in = someIdentifier + "input.txt"; 
     String out = someIdentifier + "output.txt"; 
     ProcessBuilder builder = new ProcessBuilder("./whateveer.sh", in, out); 
     try { 
      Process process = builder.start(); 
      process.waitFor(); 
     } catch (IOException e) { 
      log.error("Could not launch process. Command: " + builder.command(), e); 
     } catch (InterruptedException ex) { 
      log.error(ex); 
     } 
} 

} 

whatever.sh brzmi:

R --slave --args $1 $2 <whatever1.R >> r.log  

Ładunki wystąpień Whatever są przekazywane do ExecutorService o ustalonej wielkości (35). Reszta aplikacji czeka na zakończenie wszystkich z nich za pomocą CountdownLatch. Wszystko działa dobrze przez kilka godzin (Scientific Linux 5.0, wersja java „1.6.0_24”) przed wyrzuceniem następujący wyjątek:

java.io.IOException: Cannot run program "./whatever.sh": java.io.IOException: error=11, Resource temporarily unavailable 
    at java.lang.ProcessBuilder.start(Unknown Source) 
... rest of stack trace omitted... 

Czy ktoś ma pomysł co to oznacza? Na podstawie wyników wyszukiwania google/bing dla java.io.IOException: error=11, nie jest to najczęstszy wyjątek i jestem całkowicie zaskoczony.

Moje dzikie i niezbyt wykształcone przypuszczenie jest takie, że mam zbyt wiele wątków próbujących uruchomić ten sam plik w tym samym czasie. Jednak odtworzenie problemu zajmuje wiele godzin, więc nie próbowałem używać mniejszej liczby.

Wszelkie sugestie są bardzo mile widziane.

+0

Czy sprawdziłeś otwartą kopię pliku procesu java za pomocą 'lsof'? – lidaobing

+1

Czy to errno 11, czy 12, czy oba? –

+0

Błąd = 11 tylko – mbatchkarov

Odpowiedz

6

error=11 jest prawie na pewno kod EAGAIN błąd:

$ grep EAGAIN asm-generic/errno-base.h 
#define EAGAIN  11 /* Try again */ 

clone(2) wywołanie systemowe dokumentuje powrót EAGAIN błędzie:

EAGAIN Too many processes are already running. 

dokumentuje wywołanie systemowe fork(2) dwa EAGAIN zwraca błąd:

EAGAIN fork() cannot allocate sufficient memory to copy the 
      parent's page tables and allocate a task structure for 
      the child. 

    EAGAIN It was not possible to create a new process because 
      the caller's RLIMIT_NPROC resource limit was 
      encountered. To exceed this limit, the process must 
      have either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE 
      capability. 

Jeśli naprawdę masz tak mało pamięci, prawie na pewno pojawi się w logach systemowych. Sprawdź dane wyjściowe dmesg(1) lub /var/log/syslog pod kątem ewentualnych komunikatów dotyczących małej ilości pamięci systemowej. (Inne rzeczy mogą się zepsuć, nie wydaje się to zbyt prawdopodobne.)

O wiele bardziej prawdopodobne jest przekroczenie przez użytkownika limitu procesów lub maksymalnej liczby procesów w całym systemie. Być może jednym z twoich procesów nie jest poprawne ponowne zombianie? Byłoby to bardzo łatwe do wykrycia przez sprawdzenie ps(1) wyjście w czasie:

while true ; do ps auxw >> ~/processes ; sleep 10 ; done 

(Może sprawdzić każdą minutę lub dziesięć minut, jeśli to naprawdę bierze godzin przed jesteś w tarapatach.)

Jeśli nie zbierasz zombie, przeczytaj co trzeba zrobić, aby ProcessBuilder użył waitpid(2), aby zebrać zmarłe dzieci.

Jeśli legalnie działa więcej procesów niż rlimits pozwolić, trzeba użyć ulimit w skryptach bash(1) (jeśli działa jako root) lub ustawić wyższe limity w /etc/security/limits.conf dla właściwości nproc.

Jeśli zamiast tego występują ograniczenia systemowe dla całego systemu, może być konieczne wpisanie większej wartości do /proc/sys/kernel/pid_max. Zobacz proc(5) dla niektórych (krótkie) szczegóły.

+0

Dzięki, że poprowadziłeś mnie we właściwym kierunku. Z powodu błędu w kodzie nowy wątek został utworzony w pętli zamiast ponownego użycia istniejącego, ostatecznie powodując opisany problem. – mbatchkarov

+0

Więc to nie było 'builder.start()' call _specifically_, które zawiniło, ale tylko kawałek kodu, który spowodował zgłoszenie problemu? Dobry debugowanie. :) – sarnold

+0

Cóż, to naprawdę było 'builder.start()', które się nie udało, ale nie udało się, ponieważ inna część aplikacji wyczerpała już dostępne zasoby. Jak wspomniałeś w swoim poście, rozwidlenie procesu wymaga pewnej ilości pamięci itp. Dzięki za twoją pomoc – mbatchkarov

2

errno 11 oznacza "Zasoby czasowo niedostępne" Jest to zwykle problem z pamięcią i może uniemożliwić utworzenie wątku lub gniazda.

errno 12 oznacza "Nie można przydzielić pamięci". To jest niepowodzenie w uzyskaniu pamięci jest bezpośrednim wywołaniem pamięci (a nie zasobu, który z kolei potrzebuje pamięci).

Chciałbym spróbować zwiększyć przestrzeń wymiany twojego systemu, co powinno zapobiec temu problemowi.

Powiązane problemy