#java #multithreading
#java #многопоточность
Вопрос:
Я столкнулся с очевидной утечкой дескрипторов, но я надеюсь, что есть обходной путь или что я просто неправильно понимаю, как JRE обрабатывает потоки внутри.
Пожалуйста, обратите внимание, что ответ на этот вопрос НЕ «используйте пулы потоков и ограничьте максимальное количество одновременных потоков». Это не решает основную проблему или возможные решения, особенно если желательно очень большое количество максимально одновременных потоков.
Если я создаю и запускаю много потоков одновременно, выделяется много дескрипторов. Это имеет смысл. Однако, когда все эти потоки заканчиваются, большинство выделенных дескрипторов не освобождаются.
Количество дескрипторов из Process Explorer приведено ниже для:
Пик — Максимальное количество дескрипторов после создания и запуска 600 потоков
Завершенные потоки — Количество дескрипторов после завершения всех 600 потоков (просто оставляя основной поток и потоки JVM)
Handle Counts
JRE Peak Threads Ended
1.4 2632 232
5 3859 259
6 4311 3111
8 4321 3121
Здесь два основных замечания:
- JRE 5 и более поздние версии имеют значительно более высокие издержки обработки потоков, чем 1.4
- JRE 6 и более поздние версии не освобождают дескрипторы после завершения потоков
Многократное создание и запуск одного и того же или меньшего количества потоков не приводит к увеличению количества дескрипторов с пиковым / конечным дескриптором (за исключением использования JRE 1.5, в котором может произойти другая более медленная утечка). Увеличение максимального количества одновременных потоков увеличивает оба числа.
Все JRE, используемые для тестирования, относятся к разновидности Sun / Oracle.
GC никогда не приходит и не устраняет беспорядок, основанный на нескольких днях тестирования и наблюдения за проблемой.
Кто-нибудь знает, как гарантировать, что ресурсы дескриптора для потоков освобождаются после использования в Java 6 и более поздних версиях без перезапуска JVM?
Ниже приведен тестовый код для воспроизведения проблемы:
public class ThreadLeakTest
{
public static void main(String[] args)
{
new ThreadLeakTest();
}
public ThreadLeakTest()
{
while (true)
{
for (int i = 0; i < 600; i)
{
LeakTestThread testThread = new LeakTestThread();
Thread t = new Thread(testThread);
t.start();
}
sleepSafe(20000);
}
}
private class LeakTestThread implements Runnable
{
public void run()
{
sleepSafe(15000);
}
}
private static final void sleepSafe(int sleepTime)
{
try
{
Thread.sleep(sleepTime);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
Комментарии:
1. @GhostCat Ваш ответ подтверждает, что известно о существовании проблемы или одной очень похожей, и что официального решения пока не существует. Осведомленность других людей о проблеме не является решением проблемы. Я уже дал понять в ответ на ваш ответ, что предложения по ограничению целевой ОС и / или изменению языка программирования также не являются приемлемыми решениями. Другие пользователи могут прийти в любое время в будущем с ответами, которые решают проблему.
2. Вы спросили о проблеме, которая, похоже, является ошибкой. Для этого нет решения, кроме исправления ошибки. Помимо этого есть просто обходные пути. То, что вам нужно решение, не означает, что оно есть.
Ответ №1:
Похоже, это известная ошибка, 8154063:
Виртуальная машина поддерживает пул объектов PlatformEvent (которые сопоставляются с событиями в Windows). Этот пул увеличится до максимума, необходимого для максимального количества одновременных потоков, существующих в виртуальной машине одновременно. Обычно нам не хватает памяти для создания потоков задолго до того, как у нас закончатся дескрипторы. Таким образом, во время первого ожидания существует только основной поток и несколько потоков виртуальной машины, а общее количество дескрипторов невелико.
Затем мы запускаем 3000 потоков, каждый из которых использует как минимум 5 дескрипторов (и, основываясь на сообщаемых выходных данных, я предполагаю, что где-то в реализации скрывается 6-й дескриптор). Тогда в зависимости от размера машины и планирования будет некоторое различие в количестве одновременных потоков, но предположим, что всего 3000, и легко увидеть, откуда берутся максимальные значения.
Таким образом, здесь, похоже, нет хорошего решения для Windows, кроме уменьшения количества потоков. Помимо этого, более общая мысль: кажется, что вы используете свое оборудование для «реальных» серверных задач. Если это так, рассмотрите:
- использование ОС, которая тогда лучше работала с Java (есть причина, по которой в наши дни так много крупных серверов работают под управлением Linux)
- если вам нужно остаться с Windows, вы могли бы либо рассмотреть возможность использования платформы, которая «ближе» к ней, например .NET и C #. Или вы выбираете платформу JVM, такую как Akka, которая обеспечивает свой «параллелизм» без большого количества потоков.
Комментарии:
1. Спасибо за ссылку на сообщение об ошибке. На этой странице (8154063) говорится, что отчет об ошибке является дубликатом 8145999. Однако 8145999, похоже, скрыт от общего просмотра, поэтому статус неизвестен. проблема в 8u202 все еще существует более двух лет спустя, так что это не обнадеживает.
2. Я тоже это видел. Вот почему я перешел к этому.
3. Что касается ваших правок: требуется кроссплатформенность, поэтому я не могу склоняться к Windows или Linux. Akka не выглядит жизнеспособным вариантом для моих целей. Надеюсь, ваши предложения помогут другим, кто столкнется с этой страницей.