Mi okozza a java.lang.OutOfMemoryError alkalmazást: nem lehet új natív szálat létrehozni
1. Bemutatkozás
Ebben az oktatóanyagban megvitatjuk a probléma okát és lehetséges orvoslását java.lang.OutOfMemoryError: nem lehet új natív szálat létrehozni hiba.
2. A probléma megértése
2.1. A probléma oka
A legtöbb Java alkalmazás többszálas jellegű, amely több összetevőből áll, meghatározott feladatokat hajt végre, és különböző szálakban hajtja végre. Azonban a mögöttes az operációs rendszer (OS) korlátot szab a szálak maximális számára amelyet egy Java alkalmazás létrehozhat.
A JVM dob egy nem tud új natív szálat létrehozni hiba, amikor a A JVM új szálat kér az alapul szolgáló operációs rendszertől, és az operációs rendszer nem képes új rendszermag-szálak létrehozására, más néven operációs rendszer vagy rendszerszálak. Az események sorrendje a következő:
- A Java virtuális gépen (JVM) belül futó alkalmazás új szálat kér
- A JVM natív kód kérést küld az operációs rendszer számára egy új kernl szál létrehozására
- Az operációs rendszer megkísérel egy új kernelszálat létrehozni, amely memóriafoglalást igényel
- Az operációs rendszer elutasítja a natív memória kiosztását, mert egyik sem
- A kérő A Java folyamat kimerítette memória címterét
- Az operációs rendszer kimerítette virtuális memóriáját
- A Java folyamat ezután visszaadja a java.lang.OutOfMemoryError: nem lehet új natív szálat létrehozni hiba
2.2. Menetallokációs modell
Egy operációs rendszer általában rendelkezik kétféle szál - felhasználói szálak (Java alkalmazás által létrehozott szálak) és kernel szálak. A felhasználói szálak a kernelszálak felett támogatottak, és a kernelszálakat az operációs rendszer kezeli.
Közöttük három közös kapcsolat van:
- Sok-az-egyhez - Sok felhasználói szál egyetlen kernlaphoz kapcsolódik
- 1-1 - Egy felhasználói szál leképezése egy kernel szálra
- Sok-sok-sok - Sok felhasználói szál multiplexel kisebb vagy azonos számú kernelszálhoz
3. A hiba megismétlése
Könnyen újrateremthetjük ezt a problémát, ha szálakat hozunk létre egy folyamatos ciklusban, majd várakoztatjuk a szálakat:
while (true) {new Thread (() -> {try {TimeUnit.HOURS.sleep (1);} catch (InterruptedException e) {e.printStackTrace ();}}). start (); }
Mivel egy órán át ragaszkodunk az egyes szálakhoz, miközben folyamatosan újakat hozunk létre, gyorsan elérjük az operációs rendszer maximális szálainak számát.
4. Megoldások
A hiba elhárításának egyik módja a szálkorlát-konfiguráció növelése az operációs rendszer szintjén.
Ez azonban nem ideális megoldás, mert a OutOfMemoryError valószínűleg programozási hibát jelez. Vizsgáljuk meg a probléma megoldásának néhány más módját.
4.1. Az Executor Service Framework kihasználása
A Java végrehajtó szolgáltatási keretrendszerének felhasználása a száladminisztrációhoz bizonyos mértékben megoldhatja ezt a problémát. Az alapértelmezett végrehajtói szolgáltatási keretrendszer vagy egy egyedi végrehajtó konfiguráció vezérelheti a szálak létrehozását.
Használhatjuk a Végrehajtók # newFixedThreadPool módszer az egyszerre felhasználható szálak maximális számának beállításához:
ExecutorService végrehajtóService = Executors.newFixedThreadPool (5); Futható runnableTask = () -> {próbálkozzon a {TimeUnit.HOURS.sleep (1); } catch (InterruptedException e) {// Kivétel kezelése}}; IntStream.rangeClosed (1, 10) .forEach (i -> executorService.submit (runnableTask)); assertThat ((((ThreadPoolExecutor) executorService) .getQueue (). size (), is (equalTo (5)));
A fenti példában először egy szálas rögzített szálat hozunk létre öt szálból és egy futtatható feladattól, amely a szálakat egy órán át várja. Ezután tíz ilyen feladatot adunk be a szálkészletbe, és azt állítjuk, hogy öt feladat vár a végrehajtói szolgáltatás sorában.
Mivel a szálkészletnek öt szála van, ezért maximum öt feladatot képes bármikor kezelni.
4.2. A szálkép rögzítése és elemzése
A szállekép rögzítése és elemzése hasznos a szál állapotának megértéséhez.
Nézzünk meg egy szál lerakódást, és nézzük meg, mit tanulhatunk:
A fenti szál pillanatkép a Java VisualVM-től származik a korábban bemutatott példához. Ez a pillanatkép egyértelműen bemutatja a folyamatos szálalkotást.
Miután azonosítottuk, hogy folyamatos a szál létrehozása, rögzíthetjük az alkalmazás szálkiadását, hogy azonosítsuk a szálakat létrehozó forráskódot:
A fenti pillanatképben azonosíthatjuk a szál létrehozásáért felelős kódot. Ez hasznos betekintést nyújt a megfelelő intézkedések megtételéhez.
5. Következtetés
Ebben a cikkben megtudtuk a java.lang.OutOfMemoryError: nem lehet új natív szálat létrehozni hiba, és ezt láttuk a túlzott szálalkotás okozza Java alkalmazásban.
Felfedeztünk néhány megoldást a hiba kezelésére és elemzésére a ExecutorService a keretrendszer és a szál dump elemzés, mint két hasznos intézkedés ennek a kérdésnek a kezelésére.
Mint mindig, a cikk forráskódja elérhető a GitHubon.