Java >> Java tutorial >  >> Tag >> java.lang

Hvad forårsager java.lang.OutOfMemoryError:kan ikke oprette ny indbygget tråd

1. Introduktion

I dette selvstudie vil vi diskutere årsagen til og mulige løsninger på java.lang.OutOfMemoryError:ikke i stand til at oprette ny indbygget tråd fejl.

2. Forstå problemet

2.1. Årsag til problemet

De fleste Java-applikationer er multithreaded i naturen , der består af flere komponenter, udfører specifikke opgaver og udføres i forskellige tråde. Det underliggende operativsystem (OS) pålægger dog et loft over det maksimale antal tråde som en Java-applikation kan oprette.

JVM'et sender en ikke i stand til at oprette ny indbygget tråd  fejl, når JVM beder det underliggende OS om en ny tråd, og OS er ude af stand til at skabe nye kernetråde også kendt som OS eller systemtråde . Begivenhedsforløbet er som følger:

  1. Et program, der kører inde i Java Virtual Machine (JVM) anmoder om en ny tråd
  2. Den oprindelige JVM-kode sender en anmodning til operativsystemet om at oprette en ny kernetråd
  3. OS'et forsøger at oprette en ny kernetråd, som kræver hukommelsesallokering
  4. OS'et afviser native memory allokering, fordi enten
    • Den anmodende Java-proces har opbrugt sin hukommelsesadresseplads
    • OS'et har opbrugt sin virtuelle hukommelse
  5. Java-processen returnerer derefter java.lang.OutOfMemoryError:Kan ikke oprette ny indbygget tråd fejl

2.2. Trådfordelingsmodel

Et OS har typiskto typer tråde – brugertråde (tråde oprettet af en Java-applikation) og kernetråde . Brugertråde understøttes over kernetrådene, og kernetrådene administreres af OS.

Mellem dem er der tre almindelige forhold:

  1. Mange-til-en – Mange brugertråde er knyttet til en enkelt kernetråd
  2. En-til-en – En brugertråd kort til én kernetråd
  3. Mange-til-mange – Mange brugertråde multiplekser til et mindre eller lige så stort antal kernetråde

3. Gengivelse af fejlen

Vi kan nemt genskabe dette problem ved at oprette tråde i en kontinuerlig løkke og derefter få trådene til at vente:

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

Da vi holder på hver tråd i en time, mens vi løbende opretter nye, når vi hurtigt det maksimale antal tråde fra OS.

4. Løsninger

En måde at løse denne fejl på er at øge trådgrænsekonfigurationen på OS-niveau.

Dette er dog ikke en ideel løsning, fordi OutOfMemoryError indikerer sandsynligvis en programmeringsfejl. Lad os se på nogle andre måder at løse dette problem på.

4.1. Udnyttelse af Executor Service Framework

Udnyttelse af Javas executor-serviceramme til trådadministration kan løse dette problem til en vis grad. Standard executor-servicerammerne eller en brugerdefineret executor-konfiguration kan styre oprettelsen af ​​tråde.

Vi kan bruge Executors#newFixedThreadPool metode til at indstille det maksimale antal tråde, der kan bruges ad gangen:

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

I ovenstående eksempel opretter vi først en fast-trådspulje med fem tråde og en kørebar opgave, som får trådene til at vente i en time. Vi sender derefter ti sådanne opgaver til trådpuljen og hævder, at fem opgaver venter i eksekveringsservicekøen.

Da trådpuljen har fem tråde, kan den maksimalt håndtere fem opgaver til enhver tid.

4.2. Indfangning og analyse af tråddumpen

At fange og analysere tråddumpet er nyttigt for at forstå en tråds status.

Lad os se på et eksempel på tråddump og se, hvad vi kan lære:

Ovenstående tråd-øjebliksbillede er fra Java VisualVM til eksemplet præsenteret tidligere. Dette øjebliksbillede demonstrerer tydeligt den kontinuerlige trådoprettelse.

Når vi har identificeret, at der er kontinuerlig trådoprettelse, kan vi fange applikationens tråddump for at identificere kildekoden, der skaber trådene:

I ovenstående snapshot kan vi identificere koden, der er ansvarlig for trådoprettelsen. Dette giver nyttig indsigt i at træffe passende foranstaltninger.

5. Konklusion

I denne artikel lærte vi om java.lang.OutOfMemoryError:ikke i stand til at oprette ny indbygget tråd fejl, og vi så, at det er forårsaget af overdreven trådoprettelse i en Java-applikation.

Vi undersøgte nogle løsninger til at løse og analysere fejlen ved at se på ExecutorService  ramme- og tråddump-analyse som to nyttige foranstaltninger til at tackle dette problem.

Som altid er kildekoden til artiklen tilgængelig på GitHub.


Java tag