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
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). –
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
Czy sprawdziłeś, ile wątków możesz utworzyć w prostszej aplikacji? – Jivings