"Java.lang.OutOfMemoryError: Neuer nativer Thread kann nicht erstellt werden"

124

Wir bekommen "java.lang.OutOfMemoryError : unable to create new native Thread"auf 8 GB RAM VM nach 32k Threads (ps -eLF | grep -c Java)

Jedoch "top" and "free -m" shows 50% free memory available. JDk ist 64-Bit und wird sowohl mit HotSpot als auch mit JRockit versucht. Server hat Linux 2.6.18

Wir haben auch versucht, die OS stack size (ulimit -s)Grenzen zu optimieren und zu maximieren (ulimit -u), limit.conf zu erhöhen, aber alles umsonst.

Außerdem haben wir fast alle möglichen Kombinationen von Heap-Größen ausprobiert, um sie niedrig, hoch usw. zu halten.

Das Skript, mit dem wir die Anwendung ausführen, ist

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

Danke für die Antwort.

Wir haben versucht, /etc/security/limits.conf und ulimit zu bearbeiten, aber immer noch dasselbe

[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
quelle
11
Betriebssysteme können die Anzahl der Threads, die Sie erstellen können, begrenzen. Warum erstellen Sie mehr als 32.000 Threads? Ihr System verfügt höchstwahrscheinlich nicht über Tausende von Prozessorkernen. Das Erstellen so vieler Threads ist nicht sinnvoll. Verwenden Sie ExecutorServicestattdessen einen Thread-Pool ( ).
Jesper
Danke für die Antwort. Wir verwenden eine Open-Source-Bibliothek und versuchen, diese zu testen. Jede dieser Open Source-Bibliotheken erstellt so viele Threads. Aber was ich nicht verstehe, ist, wenn "top" 50% freien Speicher anzeigt, warum dann OutOfMemory Error.
Deepak Tewani
Die Open-Source-Bibliothek, die wir in der ICE4j-Bibliothek verwenden
Deepak Tewani
11
OutOfMemoryError bedeutet nicht unbedingt, dass der Heap-Speicherplatz oder der "allgemeine" RAM erschöpft war. In diesem Fall ist klar, dass der Fehler darauf zurückzuführen ist, dass das Betriebssystem nicht über die Ressourcen verfügt, um einen zusätzlichen Thread zuzuweisen. 50% freier Speicherplatz ist für diesen speziellen Fehler irrelevant.
Andrzej Doyle
1
Welche anderen Ressourcen sind zum Erstellen neuer Threads erforderlich? Wir hatten den Eindruck, dass wir möglicherweise mehr Threads erstellen können, wenn wir den Arbeitsspeicher erhöhen. Bitte führen Sie uns
Deepak Tewani

Antworten:

80

Dies ist kein Speicherproblem, obwohl der Ausnahmenname dies stark nahelegt, sondern ein Problem mit den Betriebssystemressourcen. Ihnen gehen die nativen Threads aus, dh wie viele Threads das Betriebssystem Ihrer JVM erlauben wird.

Dies ist ein ungewöhnliches Problem, da Sie selten so viele benötigen. Haben Sie viel bedingungsloses Fadenlaichen, wo die Fäden sollten, aber nicht enden?

Sie können in Betracht ziehen, Callable / Runnables unter der Kontrolle eines Executors zu verwenden, wenn dies überhaupt möglich ist. Es gibt viele Standard-Executoren mit unterschiedlichem Verhalten, die Ihr Code leicht steuern kann.

(Es gibt viele Gründe, warum die Anzahl der Threads begrenzt ist, aber sie variieren von Betriebssystem zu Betriebssystem.)

Thorbjørn Ravn Andersen
quelle
Danke für die Antwort. Wir verwenden eine Open-Source-Bibliothek ICE4j und versuchen, diese zu testen. Wir können das Thread-Limit im Betriebssystem nicht erhöhen, wenn wir wissen, dass noch 50% Speicher auf dem Server vorhanden sind.
Deepak Tewani
Möglicherweise, aber ich denke, es wird Ihnen als solches nicht helfen. Wenn Ihnen beim Auslastungstest die Ressourcen ausgehen, müssen Sie steuern können, was in Ihrer Anwendung geschieht. Warum sind 32000 Threads gleichzeitig aktiv?
Thorbjørn Ravn Andersen
Wir erstellen 11K-Clients, die 32K-Threads zum Lesen und Schreiben von Daten auf UDP-Sockets verwenden. Von diesen
32K-
Ich glaube, dieses Problem ist in modernen Webservern gelöst. Auch udp kann Pakete verlieren - aus irgendeinem Grund verwenden Sie nicht nur einen Webserver?
Thorbjørn Ravn Andersen
7
Weil die OutOfMemory-Ausnahme OutOfResources heißen sollte. Das Betriebssystem kann die benötigte Ressource nicht bereitstellen. (Und es stellte sich heraus, dass ich ice4j nicht kannte)
Thorbjørn Ravn Andersen
14

Beim Auslastungstest ist dasselbe Problem aufgetreten. Der Grund dafür ist, dass JVM keinen neuen Java-Thread erstellen kann. Unten finden Sie den JVM-Quellcode

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);`

Grundursache: JVM löst diese Ausnahme aus, wenn JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR (Ressourcen erschöpft (bedeutet Speicher erschöpft)) oder JVMTI_RESOURCE_EXHAUSTED_THREADS (Threads erschöpft).

In meinem Fall erstellt Jboss zu viele Threads, um die Anforderung zu bedienen, aber alle Threads sind blockiert. Aus diesem Grund ist JVM sowohl mit Threads als auch mit Speicher erschöpft (jeder Thread enthält Speicher, der nicht freigegeben wird, da jeder Thread blockiert ist).

Bei der Analyse der Java-Thread-Dumps wurden fast 61.000 Threads durch eine unserer Methoden blockiert, was dieses Problem verursacht. Unten ist der Teil des Thread-Dumps

"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
quelle
Wie wurde die Methode blockiert? Nie wieder zurückkehren?
Thorbjørn Ravn Andersen
8

Es ist wahrscheinlich, dass Ihr Betriebssystem die Anzahl der Threads, die Sie erstellen möchten, nicht zulässt oder dass Sie in der JVM ein Limit erreichen. Besonders wenn es sich um eine so runde Zahl wie 32k handelt, ist ein Limit der einen oder anderen Art ein sehr wahrscheinlicher Schuldiger.

Sind Sie sicher, dass Sie wirklich 32k-Threads benötigen? Die meisten modernen Sprachen unterstützen Pools wiederverwendbarer Threads - ich bin sicher, Java hat auch etwas vorhanden (wie der ExecutorServiceBenutzer Jesper erwähnt hat). Vielleicht könnten Sie Threads aus einem solchen Pool anfordern, anstatt manuell neue zu erstellen.

Theodoros Chatzigiannakis
quelle
1
Vielen Dank für die Antwort. Wir verwenden eine Open-Source-Bibliothek ICE4j und versuchen, diese zu laden. Wir können das Thread-Limit im Betriebssystem nicht erhöhen, wenn wir wissen, dass noch 50% Speicher auf dem Server vorhanden sind.
Deepak Tewani
1
Wir erstellen 11K-Clients, die 32K-Threads zum Lesen und Schreiben von Daten auf UDP-Sockets verwenden. Von diesen
32K-
7

Ich würde empfehlen, auch die Thread-Stapelgröße zu überprüfen und zu prüfen, ob weitere Threads erstellt werden. Die Standardgröße für den Thread-Stapel für JRockit 1.5 / 1.6 beträgt 1 MB für 64-Bit-VMs unter Linux. 32K-Threads benötigen eine erhebliche Menge an physischem und virtuellem Speicher, um diese Anforderung zu erfüllen.

Versuchen Sie, die Stapelgröße als Ausgangspunkt auf 512 KB zu reduzieren, und prüfen Sie, ob dadurch mehr Threads für Ihre Anwendung erstellt werden können. Ich empfehle außerdem, die horizontale Skalierung zu untersuchen, z. B. die Aufteilung Ihrer Anwendungsverarbeitung auf mehrere physische oder virtuelle Maschinen.

Bei Verwendung einer 64-Bit-VM hängt das tatsächliche Limit von der Verfügbarkeit des physischen und virtuellen Speichers des Betriebssystems und von Betriebssystemoptimierungsparametern wie ulimitc ab. Ich empfehle auch den folgenden Artikel als Referenz:

OutOfMemoryError: Neuer nativer Thread kann nicht erstellt werden - Problem entmystifiziert

PH
quelle
5

Wenn jvm über systemd gestartet wird, gibt es in einigen Linux-Betriebssystemen möglicherweise eine maximale Anzahl von Aufgaben pro Prozess (Aufgaben bedeuten tatsächlich Threads).

Sie können dies überprüfen, indem Sie "Dienststatus" ausführen und prüfen, ob es ein maxTasks-Limit gibt. Wenn dies der Fall ist, können Sie es entfernen, indem Sie /etc/systemd/system.conf bearbeiten und eine Konfiguration hinzufügen: DefaultTasksMax = unendlich

Clement.Xu
quelle
3

Ich hatte das gleiche Problem aufgrund von Geisterprozessen, die bei der Verwendung von top in bash nicht angezeigt wurden. Dies verhinderte, dass die JVM mehr Threads erzeugt.

Für mich wurde es aufgelöst, als alle Java-Prozesse mit jps aufgelistet wurden (einfach jpsin Ihrer Shell ausführen ) und separat mit dem kill -9 pidBefehl bash für jeden Ghost-Prozess beendet wurden.

Dies kann in einigen Szenarien hilfreich sein.

mac7
quelle
2

Sie haben die Möglichkeit, sich dem java.lang.OutOfMemoryError: Unable to create new native threadProblem zu stellen, wenn die JVM vom Betriebssystem nach einem neuen Thread fragt. Immer wenn das zugrunde liegende Betriebssystem keinen neuen nativen Thread zuweisen kann, wird dieser OutOfMemoryError ausgelöst. Das genaue Limit für native Threads ist sehr plattformabhängig. Es wird daher empfohlen, diese Limits durch Ausführen eines Tests zu ermitteln, der dem folgenden Linkbeispiel ähnelt. Im Allgemeinen java.lang.OutOfMemoryError: Unable to create new native threaddurchläuft die verursachende Situation jedoch die folgenden Phasen:

  1. Ein neuer Java-Thread wird von einer Anwendung angefordert, die in der JVM ausgeführt wird
  2. Der native JVM-Code überträgt die Anforderung zum Erstellen eines neuen nativen Threads an das Betriebssystem. Das Betriebssystem versucht, einen neuen nativen Thread zu erstellen, für den dem Thread Speicher zugewiesen werden muss
  3. Das Betriebssystem verweigert die native Speicherzuweisung entweder, weil die 32-Bit-Java-Prozessgröße den Speicheradressraum aufgebraucht hat - z. B. wurde die Prozessgrößenbeschränkung von (2-4) GB erreicht - oder der virtuelle Speicher des Betriebssystems vollständig aufgebraucht ist
  4. Der Fehler java.lang.OutOfMemoryError: Es kann kein neuer nativer Thread erstellt werden.

Referenz: https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread

Sazzad Hissain Khan
quelle
2

Um herauszufinden, welche Prozesse Threads erstellen, versuchen Sie:

ps huH

Normalerweise leite ich die Ausgabe in eine Datei um und analysiere die Datei offline (die Anzahl der Threads für jeden Prozess ist wie erwartet oder nicht).

user8521771
quelle
1

Wenn Ihr Job aufgrund von OutOfMemmory auf Knoten fehlschlägt, können Sie die Anzahl der maximalen Maps und Reduzierer überprüfen und die JVM für jeden auswählen. mapred.child.java.opts (der Standardwert ist 200Xmx) muss normalerweise basierend auf der spezifischen Hardware Ihrer Datenknoten erhöht werden.

Dieser Link könnte hilfreich sein ... bitte überprüfen

Pavan Kumar K.
quelle
1
Wir haben alle bereits versucht, diese Änderung auf diesem Link vorzunehmen. Aber das Ergebnis ist das gleiche :(
Deepak Tewani
1

Ihre JBoss-Konfiguration weist einige Probleme auf. /opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m Xms und Xmx beschränken Ihre JBoss-Speichernutzung auf den konfigurierten Wert, sodass der Server ab 8 GB nur 512 MB verwendet + etwas mehr für seinen eigenen Zweck, erhöhen Sie diese Zahl, denken Sie daran, etwas für das Betriebssystem und andere Dinge, die dort laufen, frei zu lassen, und möglicherweise bringen Sie es trotz des unappetitlichen Codes zum Laufen. Das Reparieren des Codes wäre auch schön, wenn Sie können.

user3390284
quelle
1

Dieser Fehler kann aus folgenden zwei Gründen auftreten:

  • Im Speicher ist kein Platz für neue Threads.

  • Die Anzahl der Threads überschreitet das Betriebssystemlimit.

Ich bezweifle, dass die Anzahl der Threads das Limit für den Java-Prozess überschritten hat

Möglicherweise liegt das Problem also am Gedächtnis. Ein zu berücksichtigender Punkt ist

Threads werden nicht im JVM-Heap erstellt. Sie werden außerhalb des JVM-Heaps erstellt. Wenn also nach der JVM-Heap-Zuweisung weniger Speicherplatz im RAM vorhanden ist, wird die Anwendung in "java.lang.OutOfMemoryError: Neuer nativer Thread kann nicht erstellt werden" ausgeführt.

Mögliche Lösung besteht darin, den Heapspeicher zu reduzieren oder die Gesamtgröße des RAM zu erhöhen

Einzelgänger
quelle
0

Ich hatte das gleiche Problem und es stellte sich heraus, dass eine Java-API nicht ordnungsgemäß verwendet wurde. Ich habe einen Builder in einer Stapelverarbeitungsmethode initialisiert, die nicht mehr als einmal initiiert werden sollte.

Im Grunde habe ich so etwas gemacht wie:

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

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

wann ich das hätte tun sollen:

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

def process_batch(batch, client) {
    client.processList(batch)
}
Anthonybell
quelle
-4

Zuallererst würde ich nicht so sehr das Betriebssystem / die VM beschuldigen, sondern den Entwickler, der den Code geschrieben hat, der sooo viele Threads erstellt . Grundsätzlich werden irgendwo in Ihrem Code (oder in einem Drittanbieter) viele Threads ohne Kontrolle erstellt .

Überprüfen Sie die Stacktraces / den Code sorgfältig und steuern Sie die Anzahl der erstellten Threads. Normalerweise sollte Ihre App nicht viele Threads benötigen, wenn dies der Fall ist, handelt es sich um ein anderes Problem.

Flueras Bogdan
quelle
10
Dies ist keine Lösung für die Frage.
Ftrujillo