Hva forårsaker java.lang.OutOfMemoryError: kan ikke opprette ny innfødt tråd

1. Introduksjon

I denne opplæringen vil vi diskutere årsaken og mulige løsninger for java.lang.OutOfMemoryError: kan ikke opprette ny innfødt tråd feil.

2. Forstå problemet

2.1. Årsak til problemet

De fleste Java-applikasjoner har flertrådet natur, bestående av flere komponenter, utfører spesifikke oppgaver, og utføres i forskjellige tråder. Imidlertid er den underliggende operativsystem (OS) pålegger maksimalt antall tråder som et Java-program kan opprette.

JVM kaster en kan ikke opprette ny innfødt tråd feil når JVM ber det underliggende operativsystemet om en ny tråd, og operativsystemet er ikke i stand til å opprette nye kjernetråder, også kjent som OS eller systemtråder. Hendelsesforløpet er som følger:

  1. Et program som kjører inne i Java Virtual Machine (JVM), ber om en ny tråd
  2. Den opprinnelige JVM-koden sender en forespørsel til operativsystemet om å opprette en ny kjernetråd
  3. OS prøver å lage en ny kjernetråd som krever minnetildeling
  4. Operativsystemet nekter tildeling av innfødt minne fordi enten
    • Den ber om Java-prosessen har brukt opp minneadresseplassen
    • OS har tømt sitt virtuelle minne
  5. Java-prosessen returnerer deretter java.lang.OutOfMemoryError: kan ikke opprette ny innfødt tråd feil

2.2. Trådallokeringsmodell

Et operativsystem har vanligvis to typer tråder - brukertråder (tråder opprettet av et Java-program) og kjernetråder. Brukertråder støttes over kjernetrådene, og kjernetrådene administreres av operativsystemet.

Mellom dem er det tre vanlige forhold:

  1. Mange-mot-en - Mange brukertråder tilordnes til en enkelt kjernetråd
  2. En-mot-en - En brukertrådekart til en kjernetråd
  3. Mange-til-mange - Mange brukertråder er multipleksede til et mindre eller like antall kjernetråder

3. Gjengi feilen

Vi kan enkelt gjenskape dette problemet ved å lage tråder i en kontinuerlig sløyfe og deretter få trådene til å vente:

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

Siden vi holder på hver tråd i en time, mens vi kontinuerlig lager nye, vil vi raskt nå det maksimale antallet tråder fra operativsystemet.

4. Løsninger

En måte å løse denne feilen på er å øke trådgrense-konfigurasjonen på OS-nivå.

Dette er imidlertid ikke en ideell løsning fordi OutOfMemoryError indikerer sannsynligvis en programmeringsfeil. La oss se på noen andre måter å løse dette problemet på.

4.1. Leveraging Executor Service Framework

Utnyttelse av Java's executor service framework for thread administration kan løse dette problemet til en viss grad. Standard eksekverer-servicerammeverk, eller en tilpasset eksekveringskonfigurasjon, kan kontrollere opprettingen av tråden.

Vi kan bruke Eksekutører # newFixedThreadPool metode for å angi maksimalt antall tråder som kan brukes om gangen:

ExecutorService executorService = Executors.newFixedThreadPool (5); Runnable runnableTask = () -> {prøv {TimeUnit.HOURS.sleep (1); } fange (InterruptedException e) {// Handle Exception}}; IntStream.rangeClosed (1, 10) .forEach (i -> executorService.submit (runnableTask)); assertThat ((((ThreadPoolExecutor) executorService) .getQueue (). størrelse (), er (equalTo (5)));

I eksemplet ovenfor lager vi først et basseng med fast tråd med fem tråder og en kjørbar oppgave som får trådene til å vente i en time. Vi sender deretter ti slike oppgaver til trådpuljen og hevder at fem oppgaver venter i eksekutortjenestekøen.

Siden trådgruppen har fem tråder, kan den håndtere maksimalt fem oppgaver når som helst.

4.2. Fange og analysere tråddumpen

Å fange og analysere tråddumpen er nyttig for å forstå statusen til en tråd.

La oss se på et eksempel på tråddumping og se hva vi kan lære:

Ovenstående trådbilde er fra Java VisualVM for eksemplet som ble presentert tidligere. Dette øyeblikksbildet viser tydelig den kontinuerlige trådopprettingen.

Når vi har identifisert at det er kontinuerlig trådoppretting, kan vi fange tråddumpen til applikasjonen for å identifisere kildekoden som lager trådene:

I øyeblikksbildet ovenfor kan vi identifisere koden som er ansvarlig for opprettelsen av tråden. Dette gir nyttig innsikt for å treffe passende tiltak.

5. Konklusjon

I denne artikkelen lærte vi om java.lang.OutOfMemoryError: kan ikke opprette ny innfødt tråd feil, og vi så det det er forårsaket av overdreven trådoppretting i et Java-program.

Vi undersøkte noen løsninger for å løse og analysere feilen ved å se på ExecutorService rammeverk og tråddumpanalyse som to nyttige tiltak for å takle dette problemet.

Som alltid er kildekoden for artikkelen tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found