2012-05-24 11 views
11

Czytałem, testowałem i waliłem głową w ścianę przez ponad jeden dzień z powodu tego błędu.Java `OutOfMemoryError` podczas tworzenia <100 wątków

mam trochę kodu Java w klasie o nazwie Listener że wygląda tak

ExecutorService executor = Executors.newFixedThreadPool(NTHREADS); 
boolean listening = true; 
int count = 0; 
while (listening) { 
    Runnable worker; 
    try { 
     worker = new ServerThread(serverSocket.accept()); // this is line 254 
     executor.execute(worker); 
     count++; 
     logger.info("{} threads started", count); 
    } catch (Exception e1){ 
     //... 
    } 
} 

I zostały szczypanie JVM Settings -Xmx (wszędzie od 1 do 15 g) i -Xss (wszędzie od 104k do 512MB). Serwer ma 24 GB pamięci RAM, ale musi również uruchomić bazę danych obsługującą program.

Po 2-20 wątki są tworzone (kilkadziesiąt istnieją gdzie indziej w programie, jak również), pojawia się błąd

Exception in thread "Thread-0" java.lang.OutOfMemoryError: unable to create new native thread 
at java.lang.Thread.start0(Native Method) 
at java.lang.Thread.start(Thread.java:657) 
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:943) 
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1325) 
at xxx.Listener.run(Listener.java:254) 

$java -version plonów:

java version "1.6.0_24" 
OpenJDK Runtime Environment (IcedTea6 1.11.1) (fedora-65.1.11.1.fc16-x86_64) 
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode) 

zawsze jest duża ilość wolnej pamięci w systemie, gdy tak się dzieje, a inne programy nadal działają prawidłowo. Co powoduje, że Java nie ma więcej pamięci na nowe wątki?

UPDATE: Być może ten jest większy niż Myślałam udało mi się tego błędu (tylko jeden raz), gdy użyłem ^C:

OpenJDK 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated 

i to samo się stało, kiedy próbował zabić klient (również napisany w Javie i działający na tym samym serwerze, jest to pojedynczy wątek, który odczytuje plik i wysyła go na serwer przez gniazdo), więc z pewnością istnieje ograniczenie poza maszyną JVM, która powoduje interferencję z drugą, ale nie mogę sobie wyobrazić, co jeśli nadal mam wolną pamięć i nie używam w ogóle zamiany? Serwer -Xmx1G -Xss104k Client -Xmx10M

Update2: Porzucenie Perl Forks::Super bibliotekę i prowadzenie klientów z bash pozwól mi wstać do 34 wątków zanim serwer rozbił się z OOME, więc uruchomienie wielu klientów z pewnością miał wpływ na serwerze, ale jednocześnie powinienem być w stanie uruchomić więcej niż 34 (68 jeśli zlicza się klientów) wątki java na raz. Które zasoby systemowe blokują tworzenie większej liczby wątków (np. Gdzie powinienem szukać, aby znaleźć hog)? Kiedy wszystko (klienci, serwer, GC ...) zabraknie pamięci w tym samym czasie, top mówi to o moim procesora i pamięci użytkowania:

Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Mem: 24681040k total, 1029420k used, 23651620k free, 30648k buffers 
Swap: 26836988k total,  0k used, 26836988k free, 453620k cached 

UPDATE3: robi dziennik hs_error poniżej wskazują, że mój Java nie jest 64-bitowy?

# There is insufficient memory for the Java Runtime Environment to continue. 
# Cannot create GC thread. Out of system resources. 
# Possible reasons: 
# The system is out of physical RAM or swap space 
# In 32 bit mode, the process size limit was hit 
# Possible solutions: 
# Reduce memory load on the system 
# Increase physical memory or swap space 
# Check if swap backing store is full 
# Use 64 bit Java on a 64 bit OS 
# Decrease Java heap size (-Xmx/-Xms) 
# Decrease number of Java threads 
# Decrease Java thread stack sizes (-Xss) 
# Set larger code cache with -XX:ReservedCodeCacheSize= 
# This output file may be truncated or incomplete. 
# 
# JRE version: 6.0_24-b24 
# Java VM: OpenJDK 64-Bit Server VM (20.0-b12 mixed mode linux-amd64 compressed oops) 
# Derivative: IcedTea6 1.11.1 
# Distribution: Fedora release 16 (Verne), package fedora-65.1.11.1.fc16-x86_64 
+0

Czy wystąpił ServerThread w java.lang.Thread? to powinno zaczynać się od Thread.start(), a pula wątków jest bezużyteczna. Jeśli nie, to w jaki sposób zamierzasz obsłużyć połączenie przez gniazdo z prostym Runnable? Jest to trudne, ponieważ zadania kontrolowane przez wątek nie mogą czekać na dane wejściowe, lub może wystąpić głodzenie wątków (rodzaj impasu). –

+0

ServerThread jest kiepsko nazwaną klasą mojego własnego tworzenia 'public class ServerThread implements Runnable {... public void run() {...} ...}' Widzę twoją obawę, że może być źle czekać na wejście do puli (jest funkcja timeout), ale nie chcę tworzyć nowego wątku za każdym razem, gdy klient się połączy - byłoby to ogromne obciążenie dla relatywnie krótkich interakcji i nadal nie rozwiązałoby problemów z tworzeniem wątków. – kaz

+0

Czy sprawdziłeś, ile wątków możesz utworzyć w prostszej aplikacji? – Jivings

Odpowiedz

11

Możesz być granica przez max user processes, aby znać swój limit użycia:

ulimit -u 

Aby zmienić limit:

W /etc/security/limits.conf zestawie

user soft nproc [your_val] 
user hard nproc [your_val] 

Być może trzeba będzie dodać kilka inna konfiguracja, jeśli to za mało zobacz ten link.

Uwaga: OP znalazł ten bug report w Fedorze i centos, co wyjaśnia ograniczenia edycji /etc/security/limits.conf.

+0

Byłbym przeklęty, jeśli to * jest przyczyną mojego bólu głowy z wersją Centos 6, której używam. wildcard (*) karane na wolności. Nie tylko ja, ale profesjonalni faceci najwyraźniej o tym nie wiedzieli – nir

3

Twój problem jest prawdopodobnie związany z tym, że JVM nie może przydzielić pamięci stosu dla nowych wątków. Jak na ironię, ten problem można rozwiązać, zmniejszając przestrzeń sterty (-Xmx) i przestrzeń stosu (-Xss). Sprawdź tutaj, na przykład, dla dobrego wyjaśnienia: http://www.blogsoncloud.com/jsp/techSols/java-lang-OutOfMemoryError-unable-to-create-new-native-thread.jsp

+0

Chciałbym, żeby było tak proste, ale jakoś z '-Xmx1G -Xss104k'I udało mi się stworzyć 6 wątków (w sumie mniej niż 40 jawnie utworzonych w moim programie).104k to minimalna wartość -Xss w moim systemie, a 1G nie jest nawet tak duży, jak powinien być w produkcji. Tymczasem w systemie brakuje jeszcze dużej ilości (ponad 8G), gdy zabraknie jej pamięci. – kaz

+0

104k to dziwna wartość :) ten dokument mówi o minimum 64k http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom –

+0

Dziwne, ale gdy uruchamiam JVM z mniej niż 104, wyrzuca tę wiadomość i ulega awarii: 'Określony rozmiar stosu jest za mały, Określ co najmniej 104k Nie można utworzyć maszyny wirtualnej Java." – kaz

3

Nie brakuje pamięci dla nowych wątków, brakuje rzeczywistych wątków. System prawdopodobnie Cię zatrzymuje: istnieje ograniczenie liczby wątków, które użytkownik może utworzyć.można wyszukać go w ten sposób:

cat /proc/sys/kernel/threads-max 

pamiętać, że może mieć wpływ innych procesów na tej samej maszynie, to tworzą one zbyt wiele nici. Można znaleźć na to pytanie przydatne: Maximum number of threads per process in Linux?

+0

'$ cat/proc/sys/kernel/threads-max' zwraca 385345- na serwerze uruchamiając mój program, kilka powłok ssh/bash i MySQL, nie sądzę, żebym osiągnął ten limit. Ponadto, niektóre szczególnie okropne ustawienia jvm powodują jego śmierć po utworzeniu mniejszej liczby wątków niż innych, co sugeruje, że jest to problem związany z JVM. – kaz

1

Tylko dla wyjaśnienia:

podać ServerSocket do Thread. Czy wysyłasz dane do tego gniazda? Może przechowujesz dużo danych w kontekście wątku. Wyszukaj wzór, w którym przechowujesz Streamdata w postaci byte[].

+0

Nie, zapewniam 'Socket' do wątku,' ServerSocket.accept() 'zwraca obiekt' Socket'. I tak, przekazuję dane z innego programu i czytam te dane, przetwarzam je, a następnie rozłączam. W wersji testowej wątek tylko akceptuje gniazdo, czeka, a następnie zamyka i umiera. Gniazdo zostanie odczytane jak strumień, więc nie myślę, że przekazuję całą zawartość tego strumienia do wątku. Co więcej, dopóki klient nie uwierzytelni się, nie wysyła danych, do bufora strumieniowego będzie tylko kilkaset bajtów. – kaz