„Java.lang.OutOfMemoryError: nie można utworzyć nowego natywnego wątku”

124

Otrzymujemy "java.lang.OutOfMemoryError : unable to create new native Thread"na 8GB RAM VM po 32k wątkach (ps -eLF | grep -c java)

Jednak "top" and "free -m" shows 50% free memory available. JDk jest 64-bitowy i wypróbowany zarówno z HotSpot, jak i JRockit.Server ma Linuksa 2.6.18

Próbowaliśmy również OS stack size (ulimit -s)podkręcać i maksymalizować limity procesu (ulimit -u), zwiększać limit.conf, ale wszystko na próżno.

Wypróbowaliśmy również prawie wszystkie możliwe kombinacje rozmiarów sterty, utrzymując je na niskim, wysokim itp.

Skrypt, którego używamy do uruchamiania aplikacji, to

/opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m -Xss128k -jar JavaNatSimulator.jar /opt/tools/jnatclients/natSimulator.properties

Dziękuję za odpowiedź.

Próbowaliśmy edytować /etc/security/limits.conf i ulimit, ale wciąż to samo

[root@jboss02 ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 72192
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 72192
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
Deepak Tewani
źródło
11
Systemy operacyjne mają ograniczenia dotyczące liczby wątków, które można utworzyć. Dlaczego tworzysz ponad 32 000 wątków? Twój system najprawdopodobniej nie ma tysięcy rdzeni procesorów, więc tworzenie tak wielu wątków nie jest przydatne. ExecutorServiceZamiast tego użyj puli wątków ( ).
Jesper
Dziękuję za odpowiedź. Używamy biblioteki open source i próbujemy ją załadować. Każda biblioteka open source tworzy tak wiele wątków. Ale czego nie rozumiem, to kiedy „top” pokazuje 50% wolnej pamięci, to dlaczego błąd OutOfMemory.
Deepak Tewani
Biblioteka open source, której używamy w bibliotece ICE4j
Deepak Tewani
11
OutOfMemoryError niekoniecznie musi oznaczać, że miejsce na stercie lub „ogólna” pamięć RAM została wyczerpana. W tym przypadku jasne jest, że awaria była spowodowana tym, że system operacyjny nie miał zasobów do przydzielenia dodatkowego wątku. Posiadanie 50% wolnej pamięci nie ma znaczenia dla tej konkretnej awarii.
Andrzej Doyle
1
Jakie są inne zasoby potrzebne do tworzenia nowych wątków. Mieliśmy wrażenie, że jeśli zwiększymy pamięć RAM, to być może uda nam się stworzyć więcej wątków. Uprzejmie prowadź nas
Deepak Tewani

Odpowiedzi:

80

Nie jest to problem z pamięcią, mimo że nazwa wyjątku bardzo to sugeruje, ale problem z zasobami systemu operacyjnego. Kończą się wątki natywne, tj. Ile wątków system operacyjny pozwoli na użycie maszyny JVM.

To rzadki problem, ponieważ rzadko potrzebujesz tak wielu. Czy masz dużo bezwarunkowego odradzania się wątków, w których wątki powinny, ale nie kończą się?

Możesz rozważyć przepisanie na używanie Callable / Runnables pod kontrolą Executora, jeśli to w ogóle możliwe. Istnieje wiele standardowych programów wykonawczych o różnym zachowaniu, które kod może łatwo kontrolować.

(Istnieje wiele powodów, dla których liczba wątków jest ograniczona, ale różnią się one w zależności od systemu operacyjnego)

Thorbjørn Ravn Andersen
źródło
Dziękuję za odpowiedź. Używamy biblioteki open source ICE4j i próbujemy ją załadować. Nie możemy zwiększyć limitu wątków w systemie operacyjnym, gdy wiemy, że na serwerze zostało 50% pamięci.
Deepak Tewani
Możliwe, ale myślę, że to ci nie pomoże. Jeśli zabraknie Ci zasobów podczas testowania obciążenia, musisz mieć możliwość kontrolowania tego, co dzieje się w Twojej aplikacji. Dlaczego masz jednocześnie aktywnych 32000 wątków?
Thorbjørn Ravn Andersen
Tworzymy klientów 11K, którzy używają 32 tys. Wątków do odczytu, zapisu danych na gniazdach UDP. Z tych 32 tys. Wątków, 10 tys. Wątków utrzymuje żywe wątki, które służą do utrzymywania gniazda otwartego
Deepak Tewani
Uważam, że ten problem został rozwiązany w nowoczesnych serwerach internetowych. Również udp może tracić pakiety - czy jest jakiś powód, dla którego nie używasz tylko serwera WWW?
Thorbjørn Ravn Andersen
7
Ponieważ wyjątek OutOfMemory powinien mieć nazwę OutOfResources. System operacyjny nie może zapewnić potrzebnych zasobów. (I okazało się, że nie znam ice4j)
Thorbjørn Ravn Andersen
14

Napotkałem ten sam problem podczas testu obciążenia, powodem jest to, że JVM nie może dalej utworzyć nowego wątku Java. Poniżej znajduje się kod źródłowy JVM

if (native_thread->osthread() == NULL) {    
// No one should hold a reference to the 'native_thread'.    
    delete native_thread;   
if (JvmtiExport::should_post_resource_exhausted()) {      
    JvmtiExport::post_resource_exhausted(        
        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | 
        JVMTI_RESOURCE_EXHAUSTED_THREADS, 
        "unable to create new native thread");    
    } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "unable to create new native thread");  
} Thread::start(native_thread);`

Główna przyczyna: JVM zgłasza ten wyjątek, gdy JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR (wyczerpane zasoby (oznacza wyczerpaną pamięć)) lub JVMTI_RESOURCE_EXHAUSTED_THREADS (wyczerpane wątki).

W moim przypadku Jboss tworzy zbyt wiele wątków, aby obsłużyć żądanie, ale wszystkie wątki są blokowane. Z tego powodu JVM jest wyczerpany wątkami, a także pamięcią (każdy wątek zawiera pamięć, która nie jest zwalniana, ponieważ każdy wątek jest zablokowany).

Po przeanalizowaniu zrzutów wątków Java zaobserwowano, że prawie 61 tys. Wątków jest blokowanych przez jedną z naszych metod, która powoduje ten problem. Poniżej znajduje się część zrzutu wątku

"SimpleAsyncTaskExecutor-16562" #38070 prio=5 os_prio=0 tid=0x00007f9985440000 nid=0x2ca6 waiting for monitor entry [0x00007f9d58c2d000]
   java.lang.Thread.State: BLOCKED (on object monitor)
Madhu Cheepati
źródło
W jaki sposób metoda blokowała się? Nigdy nie wracasz?
Thorbjørn Ravn Andersen
8

Prawdopodobnie Twój system operacyjny nie zezwala na liczbę wątków, które próbujesz utworzyć, lub osiągasz pewien limit w JVM. Zwłaszcza jeśli jest to tak okrągła liczba, jak 32 tys., Prawdopodobnie winowajcą jest taki czy inny rodzaj limitu.

Czy na pewno naprawdę potrzebujesz 32 tys. Wątków? Większość współczesnych języków obsługuje jakieś pule wątków wielokrotnego użytku - jestem pewien, że Java też ma coś na swoim miejscu (jak ExecutorServicewspomniał użytkownik Jesper). Być może mógłbyś zażądać wątków z takiej puli, zamiast ręcznie tworzyć nowe.

Theodoros Chatzigiannakis
źródło
1
Dzięki za odpowiedź Używamy biblioteki ICE4j typu open source i próbujemy ją załadować. Nie możemy zwiększyć limitu wątków w systemie operacyjnym, gdy wiemy, że na serwerze zostało 50% pamięci.
Deepak Tewani
1
Tworzymy klientów 11K, którzy używają 32 tys. Wątków do odczytu, zapisu danych na gniazdach UDP. Z tych 32-kilobajtowych wątków 10-kilobajtowych to podtrzymujące żywe wątki, które służą do utrzymywania gniazda otwartego
Deepak Tewani
7

Poleciłbym również przyjrzeć się rozmiarowi stosu wątków i sprawdzić, czy utworzono więcej wątków. Domyślny rozmiar stosu wątków dla JRockit 1,5 / 1,6 to 1 MB dla 64-bitowej maszyny wirtualnej w systemie operacyjnym Linux. Wątki 32K będą wymagały znacznej ilości pamięci fizycznej i wirtualnej, aby spełnić to wymaganie.

Spróbuj zmniejszyć rozmiar stosu do 512 KB jako punkt wyjścia i sprawdź, czy pomoże to utworzyć więcej wątków dla Twojej aplikacji. Polecam również zbadanie skalowania poziomego, np. Dzielenie przetwarzania aplikacji na więcej maszyn fizycznych lub wirtualnych.

W przypadku korzystania z 64-bitowej maszyny wirtualnej rzeczywisty limit będzie zależał od dostępności pamięci fizycznej i wirtualnej systemu operacyjnego oraz parametrów dostrajania systemu operacyjnego, takich jak ulimitc. Polecam również następujący artykuł jako odniesienie:

OutOfMemoryError: nie można utworzyć nowego wątku natywnego - problem został ujawniony

PH
źródło
6

Jeśli jvm jest uruchamiany przez systemd, może istnieć limit maxTasks na proces (zadania w rzeczywistości oznaczają wątki) w niektórych systemach operacyjnych Linux.

Możesz to sprawdzić, uruchamiając „status usługi” i sprawdzając, czy istnieje limit maxTasks. Jeśli tak, możesz go usunąć, edytując /etc/systemd/system.conf, dodając konfigurację: DefaultTasksMax = infinity

Clement.Xu
źródło
Aby to rozwinąć, jeśli włączysz SSH do serwera zainfekowanego przez systemd, a następnie uruchomisz proces Java z CLI, możesz również osiągnąć głupi limit zadań nałożony na usługę sshd .
sayap
3

Miałem ten sam problem z powodu procesów duchów, które nie pojawiały się podczas używania top w bash. Uniemożliwiło to JVM utworzenie większej liczby wątków.

U mnie rozwiązało to, wypisując wszystkie procesy java z jps (po prostu wykonaj jpsw powłoce) i zabijając je osobno za pomocą kill -9 pidpolecenia bash dla każdego procesu widma.

Może to pomóc w niektórych scenariuszach.

mac7
źródło
2

Masz szansę zmierzyć się z tym, java.lang.OutOfMemoryError: Unable to create new native threadgdy JVM poprosi o nowy wątek z systemu operacyjnego. Za każdym razem, gdy bazowy system operacyjny nie może przydzielić nowego natywnego wątku, zostanie zgłoszony ten błąd OutOfMemoryError. Dokładny limit dla wątków natywnych jest bardzo zależny od platformy, dlatego zaleca się sprawdzenie tych ograniczeń, uruchamiając test podobny do poniższego przykładu linku. Ale ogólnie rzecz biorąc, sytuacja powodująca java.lang.OutOfMemoryError: Unable to create new native threadprzechodzi przez następujące fazy:

  1. Aplikacja działająca w JVM żąda nowego wątku Java
  2. Kod macierzysty maszyny JVM przekazuje żądanie utworzenia nowego wątku natywnego do systemu operacyjnego System operacyjny próbuje utworzyć nowy wątek natywny, który wymaga przydzielenia pamięci do wątku
  3. System operacyjny odmówi alokacji pamięci natywnej, ponieważ 32-bitowy rozmiar procesu Java wyczerpał swoją przestrzeń adresową pamięci - np. Osiągnięto limit rozmiaru procesu (2-4) GB - lub pamięć wirtualna systemu operacyjnego została całkowicie wyczerpana
  4. Zgłaszany jest błąd java.lang.OutOfMemoryError: Unable to create new native thread.

Źródła: https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread

Sazzad Hissain Khan
źródło
2

Aby dowiedzieć się, które procesy tworzą wątki, spróbuj:

ps huH

Zwykle przekierowuję dane wyjściowe do pliku i analizuję plik offline (czy liczba wątków dla każdego procesu jest zgodna z oczekiwaniami, czy nie)

user8521771
źródło
1

Jeśli Twoja praca kończy się niepowodzeniem z powodu OutOfMemmory na węzłach, możesz dostosować liczbę maksymalnych map i redukcji, a JVM wybierze dla każdego z nich. mapred.child.java.opts (wartość domyślna to 200Xmx) zwykle musi zostać zwiększona w zależności od sprzętu specyficznego dla węzłów danych.

Ten link może być pomocny ... proszę sprawdzić

Pavan Kumar K.
źródło
1
Wszyscy już próbowaliśmy tej zmiany podanej w tym linku. Ale wynik jest taki sam :(
Deepak Tewani
1

twoja konfiguracja JBoss ma pewne problemy, /opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m Xms i Xmx ograniczają użycie pamięci JBoss do skonfigurowanej wartości, więc z 8Gb serwer wykorzystuje tylko 512M + trochę ekstra do jego własnych celów, zwiększ tę liczbę, pamiętaj, aby zostawić trochę wolnego dla systemu operacyjnego i innych rzeczy tam działających i być może uruchomisz go pomimo niesmacznego kodu. Naprawienie kodu też byłoby fajne, jeśli możesz.

user3390284
źródło
1

Ten błąd może pojawić się z następujących dwóch powodów:

  • W pamięci nie ma miejsca na nowe wątki.

  • Liczba wątków przekracza limit systemu operacyjnego.

Wątpię, czy liczba wątków przekroczyła limit dla procesu java

Możliwe więc, że problemem jest pamięć. Jedną kwestią do rozważenia jest

wątki nie są tworzone w stercie maszyny JVM. Są tworzone poza stertą maszyny JVM. Jeśli więc w pamięci RAM pozostanie mniej miejsca, po przydzieleniu sterty maszyny JVM aplikacja uruchomi się w trybie „java.lang.OutOfMemoryError: nie można utworzyć nowego wątku natywnego”.

Możliwym rozwiązaniem jest zmniejszenie pamięci sterty lub zwiększenie całkowitego rozmiaru pamięci RAM

Politycznie niezależny
źródło
0

Miałem ten sam problem i okazało się, że jest to niewłaściwe użycie API Java. Inicjalizowałem program budujący metodą przetwarzania wsadowego, który nie powinien być inicjalizowany więcej niż raz.

Zasadniczo robiłem coś takiego:

for (batch in batches) {
    process_batch(batch)
}

def process_batch(batch) {
    var client = TransportClient.builder().build()
    client.processList(batch)
}

kiedy powinienem był to zrobić:

for (batch in batches) {
    var client = TransportClient.builder().build()
    process_batch(batch, client)
}

def process_batch(batch, client) {
    client.processList(batch)
}
dzwonek
źródło
-4

Przede wszystkim nie winiłbym aż tak bardzo systemu operacyjnego / maszyny wirtualnej, a raczej programisty, który napisał kod, który tworzy tak wiele wątków . Zasadniczo gdzieś w Twoim kodzie (lub innej firmy) wiele wątków jest tworzonych bez kontroli .

Uważnie przejrzyj stacktraces / kod i kontroluj liczbę tworzonych wątków. Zwykle Twoja aplikacja nie powinna potrzebować dużej liczby wątków, jeśli tak, to jest to inny problem.

Flueras Bogdan
źródło
10
To nie jest rozwiązanie tego pytania.
ftrujillo