Какво причинява java.lang.OutOfMemoryError: не може да се създаде нова родна нишка

1. Въведение

В този урок ще обсъдим причината и възможните средства за отстраняване на java.lang.OutOfMemoryError: не може да създаде нова грешка на родната нишка .

2. Разбиране на проблема

2.1. Причина за проблема

Повечето Java приложения са многонишкови по природа , състоящи се от множество компоненти, изпълняващи специфични задачи и изпълнявани в различни нишки. Въпреки това, основната операционна система (OS) налага ограничение на максималния брой нишки, които Java приложение може да създаде.

JVM извежда грешка в състояние да създаде нова родна нишка, когато JVM поиска основната операционна система за нова нишка и операционната система не е в състояние да създаде нови нишки на ядрото, известни също като OS или системни нишки . Последователността на събитията е следната:

  1. Приложение, изпълняващо се в Java Virtual Machine (JVM), иска нова нишка
  2. Вътрешният код на JVM изпраща заявка до ОС за създаване на нова нишка на ядрото
  3. ОС се опитва да създаде нова нишка на ядрото, която изисква разпределение на паметта
  4. ОС отказва разпределението на родната памет, защото или
    • Заявяващият Java процес е изчерпал своето адресно пространство в паметта
    • ОС е изчерпала виртуалната си памет
  5. След това процесът Java връща java.lang.OutOfMemoryError: не може да създаде нова грешка на родната нишка

2.2. Модел за разпределение на нишки

Операционната система обикновено има два типа нишки - потребителски нишки (нишки, създадени от Java приложение) и нишки на ядрото . Потребителските нишки се поддържат над нишките на ядрото и нишките на ядрото се управляват от ОС.

Между тях има три общи взаимоотношения:

  1. Много към едно - Много потребителски нишки се преобразуват в една нишка на ядрото
  2. One-To-One - Карта на една потребителска нишка към една нишка на ядрото
  3. Много към много - Много потребителски нишки се мултиплексират към по-малък или равен брой нишки на ядрото

3. Възпроизвеждане на грешката

Можем лесно да пресъздадем този проблем, като създадем нишки в непрекъснат цикъл и след това накараме нишките да изчакат:

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

Тъй като държим всяка нишка в продължение на един час, докато непрекъснато създаваме нови, бързо ще достигнем максималния брой нишки от операционната система.

4. Решения

Един от начините за отстраняване на тази грешка е да се увеличи конфигурацията на ограничението на нишките на ниво ОС.

Това обаче не е идеалното решение, тъй като OutOfMemoryError вероятно показва грешка в програмирането. Нека разгледаме някои други начини за решаване на този проблем.

4.1. Използване на рамка за услуги на изпълнител

Използвайки изпълнителната рамка за услуги на Java за администриране на нишки, може да разреши този проблем до известна степен. Служебната рамка на изпълнител по подразбиране или персонализирана конфигурация на изпълнител може да контролира създаването на нишки.

Можем да използваме метода Executors # newFixedThreadPool , за да зададем максималния брой нишки, които могат да се използват едновременно:

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

В горния пример първо създаваме пул с фиксирана нишка с пет нишки и изпълнима задача, която кара нишките да чакат един час. След това изпращаме десет такива задачи в пула от нишки и твърди, че пет задачи чакат в опашката на услугата изпълнител.

Тъй като пулът от нишки има пет нишки, той може да обработва максимум пет задачи по всяко време.

4.2. Заснемане и анализ на изхвърлянето на нишки

Заснемането и анализирането на дъмп на нишка е полезно за разбиране на състоянието на нишката.

Нека да разгледаме примерен дъмп на нишка и да видим какво можем да научим:

Горната снимка на нишката е от Java VisualVM за примера, представен по-рано. Тази снимка ясно демонстрира непрекъснатото създаване на нишка.

След като установим, че има непрекъснато създаване на нишка, можем да заснемем нишката на приложението, за да идентифицираме изходния код, създаващ нишките:

В горната снимка можем да идентифицираме кода, отговорен за създаването на нишката. Това дава полезна информация за предприемане на подходящи мерки.

5. Заключение

В тази статия научихме за java.lang.OutOfMemoryError: не може да създаде нова грешка на родната нишка и видяхме, че това е причинено от прекомерно създаване на нишка в Java приложение.

Изследвахме някои решения за отстраняване и анализ на грешката, като разгледахме рамката ExecutorService и анализа на изхвърлянето на нишки като две полезни мерки за справяне с този проблем.

Както винаги, изходният код на статията е достъпен в GitHub.