Čo spôsobuje java.lang.OutOfMemoryError: nemožno vytvoriť nové natívne vlákno

1. Úvod

V tomto výučbe sa dozvieme o príčine a možných nápravných opatreniach java.lang.OutOfMemoryError: nie je možné vytvoriť nové natívne vlákno chyba.

2. Pochopenie problému

2.1. Príčina problému

Väčšina aplikácií Java má viacvláknový charakter, skladajúci sa z viacerých komponentov, vykonávajúcich konkrétne úlohy a vykonávaných v rôznych vláknach. Avšak podkladové operačný systém (OS) ukladá maximálny počet vlákien ktoré môže Java aplikácia vytvoriť.

JVM hádže nie je možné vytvoriť nové natívne vlákno chyba, keď JVM požiada podkladový OS o nové vlákno a OS nie je schopný vytvárať nové vlákna jadra známe aj ako OS alebo systémové vlákna. Postupnosť udalostí je nasledovná:

  1. Aplikácia spustená vo vnútri Java Virtual Machine (JVM) žiada o nové vlákno
  2. Natívny kód JVM odošle OS požiadavku na vytvorenie nového vlákna jadra
  3. OS sa pokúša vytvoriť nové vlákno jadra, ktoré vyžaduje pridelenie pamäte
  4. OS odmieta pridelenie natívnej pamäte, pretože buď
    • Žiadajúci Proces Java vyčerpal svoj adresný priestor pamäte
    • OS vyčerpal svoju virtuálnu pamäť
  5. Proces Java potom vráti java.lang.OutOfMemoryError: nie je možné vytvoriť nové natívne vlákno chyba

2.2. Model pridelenia vlákna

OS zvyčajne má dva typy vlákien - používateľské vlákna (vlákna vytvorené aplikáciou Java) a vlákna jadra. Používateľské vlákna sú podporované nad vláknami jadra a vlákna vlákna sú spravované operačným systémom.

Medzi nimi existujú tri spoločné vzťahy:

  1. Mnoho na jedného - Mnoho používateľských vlákien sa mapuje na jedno vlákno jadra
  2. Jeden na jedného - Jedno mapovanie vlákna používateľa na jedno vlákno jadra
  3. Mnoho-veľa - Mnoho používateľských vlákien multiplexuje na menší alebo rovnaký počet vlákien jadra

3. Reprodukcia chyby

Tento problém môžeme ľahko znovu vytvoriť vytvorením vlákien v nepretržitej slučke a potom ich počkať:

while (true) {new Thread (() -> {try {TimeUnit.HOURS.sleep (1);} catch (InterruptedException e) {e.printStackTrace ();}}). start (); }

Keďže sa každú hodinu držíme pri každom vlákne a pri neustálom vytváraní nových rýchlo dosiahneme maximálny počet vlákien z OS.

4. Riešenia

Jedným zo spôsobov riešenia tejto chyby je zvýšenie konfigurácie limitu vlákna na úrovni OS.

Nie je to však ideálne riešenie, pretože OutOfMemoryError pravdepodobne označuje chybu programovania. Pozrime sa na niektoré ďalšie spôsoby riešenia tohto problému.

4.1. Využívanie rámca služieb exekútora

Využitie rámca služieb Java vykonávateľa pre správu vlákien môže tento problém do istej miery vyriešiť. Vytváranie vlákien môže riadiť predvolený rámec služby vykonávateľa alebo vlastná konfigurácia vykonávateľa.

Môžeme použiť Exekútori # newFixedThreadPool metóda na nastavenie maximálneho počtu vlákien, ktoré je možné súčasne použiť:

ExecutorService executorService = Executors.newFixedThreadPool (5); Runnable runnableTask = () -> {try {TimeUnit.HOURS.sleep (1); } catch (InterruptedException e) {// Handle Exception}}; IntStream.rangeClosed (1, 10) .forEach (i -> executorService.submit (runnableTask)); assertThat (((ThreadPoolExecutor) executorService) .getQueue (). size (), is (equalTo (5)));

Vo vyššie uvedenom príklade najskôr vytvoríme fond pevných vlákien s piatimi vláknami a spustiteľnou úlohou, vďaka ktorej vlákna čakajú jednu hodinu. Potom pošleme desať takýchto úloh do fondu vlákien a potvrdíme, že päť úloh čaká vo fronte služieb exekútora.

Pretože fond vlákien má päť vlákien, dokáže kedykoľvek spracovať maximálne päť úloh.

4.2. Zachytenie a analýza výpisu vlákna

Zachytenie a analýza výpisu vlákna je užitočná na pochopenie stavu vlákna.

Pozrime sa na ukážku výpisu vlákna a zistíme, čo sa môžeme naučiť:

Vyššie uvedená snímka vlákna pochádza z Java VisualVM pre príklad uvedený vyššie. Táto snímka jasne demonštruje kontinuálne vytváranie vlákien.

Keď zistíme, že existuje nepretržité vytváranie vlákien, môžeme zachytiť výpis vlákna aplikácie a identifikovať zdrojový kód, ktorý vlákna vytvára:

Na vyššie uvedenom snímku môžeme identifikovať kód zodpovedný za vytvorenie vlákna. To poskytuje užitočný pohľad na prijatie vhodných opatrení.

5. Záver

V tomto článku sme sa dozvedeli o java.lang.OutOfMemoryError: nie je možné vytvoriť nové natívne vlákno chyba, a to sme videli je to spôsobené nadmerným vytváraním vlákien v aplikácii Java.

Preskúmali sme niektoré riešenia, aby sme chybu napravili a analyzovali pohľadom na ExecutorService analýza rámca a skládok vlákien ako dve užitočné opatrenia na riešenie tejto otázky.

Zdrojový kód článku je ako vždy k dispozícii na stránkach GitHub.