Не удалось создать новую ошибку собственного потока - но очень мало потоков используется

У нас есть приложение, которое широко развернуто (несколько сотен рабочих станций). На одном сайте (и только на одном сайте - наш продукт широко используется во многих средах) мы случайным образом получаем следующую ошибку:

java.lang.OutOfMemoryError: невозможно создать новый собственный поток   на java.lang.Thread.start0 (собственный метод)   в java.lang.Thread.start(Неизвестный источник)

Операционная система - Windows 7 64 бит Мы работаем в 32-битном JVM (1.7.0_45)

Используя диспетчер задач Windows, я вижу, что процесс имеет 39 собственных потоков (не очень много), поэтому у нас нет утечки потока в нашем приложении... Нет других процессов, потребляющих много потоков (Explorer имеет 35, jvisualvm имеет 24, iexplore имеет 20,... У меня нет точного подсчета, но мы, вероятно, смотрим, возможно, на 300 потоков для пользователя).

Я попытался подключить JVisualVM, но он не может подключиться к процессу (возможно, b/c из исчерпания потока). Но из показателей, которые я могу получить из JVisualVM, число потоков Java составляет около 22 живых и 11 демона.

Куча хорошо себя ведет - куча составляет 500 МБ с фактически используемым 250 МБ.

Процесс запускается с -Xmx512m

В нашем процессе отображается использование памяти (в диспетчере задач) 597 744 К.

Рабочая станция имеет 8 ГБ оперативной памяти, из которых только 3,8-4,0 ГБ (я знаю, 32-битный процесс не будет иметь доступ ко всему этому, но там еще много)

Используется VMMap, а стек - 49,920KB с 2,284K.

Процесс показывает 5358 КБ бесплатно, а самый большой выделяемый блок в свободном списке имеет размер 1024 байта.

Я использовал Монитор ресурсов и показывал, что Commit (KB) равен 630428, рабочий набор (KB) - 676 ​​996, Shareable (KB) - 79 252, а Private (KB) - 597 744

У меня полная потеря относительно того, что здесь происходит. Я читал тонну статей об этом, и это звучит, как на некоторых Linux-системах, существует ограничение на количество пользователей, которое может вызвать проблемы (но это не Linux, и проблемы, описанные в других статьях, обычно говорят о необходимости тысячи тем - определенно не наш случай здесь).

Если бы наша куча была действительно большой, я мог видеть, что есть в пространстве, доступном для потоков, но 500 Мбайт кажется очень разумной и маленькой кучей (esp для рабочей станции с 8 ГБ ОЗУ).

Итак, я довольно сильно измучил все, что я знаю, - есть ли у кого-нибудь дополнительные указания о том, что может происходить здесь?

ИЗМЕНИТЬ 1:

Я нашел эту интересную статью: Сбой Eclipse с "Невозможно создать новый собственный поток" - есть идеи? (мои настройки и информация внутри)

Они предполагают, что проблема с размером стека может быть проблемой.

Эта статья: где найти значение XSS по умолчанию для Sun/Oracle JVM? - дает ссылку на документацию Oracle, в которой указано, что размер стека по умолчанию составляет 512 КБ. Поэтому, если у моего приложения около 40 потоков, мы смотрим на 20 МБ стека. Куча 500 МБ. Все это, похоже, хорошо соответствует нормальным рамкам для 32-битного Java-процесса.

Итак, это оставляет мне две возможности, о которых я могу думать:

  • Некоторое переходное условие вызывает создание большого количества потоков (но эти потоки отбрасываются, прежде чем у нас есть возможность провести диагностику).
  • Сегментация памяти по какой-то причине убивает нас. Интересно, что самый большой выделяемый блок (на VMMap - 1 МБ) - это не похоже на... На другой машине, где все работает нормально, самый большой выделяемый блок - 470 МБ...

Итак, есть ли указатели на то, как проверить сегментацию памяти?

ИЗМЕНИТЬ 2:

Статья, связанная с @mikhael (http://blog.egilh.com/2006/06/2811aspx.html) дает приблизительные вычисления для разрешенных # потоков на 32-битной JVM.

Я собираюсь предположить:

Ограничение пространства ОС: 2 ГБ Современная JVM требует 250 МБ (это большое предположение - я только удвоил то, что было в связанной статье) Размер стека (по умолчанию Oracle): 512 КБ Куча: 512 МБ PermGen: (не помню точно, но это было, конечно, меньше 100 МБ, поэтому давайте просто использовать это)

Итак, у меня есть худший сценарий: (2GB -.25GB -.5GB -.1GB)/. 005GB = 230 threads

ИЗМЕНИТЬ 3:

Информация, которую я должен был включить изначально: приложение работает нормально (например, от 24 до 48 часов), прежде чем эта проблема произойдет. Приложение выполняет непрерывную фоновую обработку, поэтому имеет очень мало свободного времени. Не уверен, что это важно или нет...

ИЗМЕНИТЬ 4:

Дополнительная информация: Глядя на VMMap из-за другого сбоя, и я вижу истощение кучи.

Размер кучи составляет 1,2 ГБ, всего 59,8 МБ.

Проблема в том, что среда выполнения Java является проблемой, или, может быть, некоторая проблема с тем, что собственные ресурсы не выпущены должным образом? Как, возможно, файл с отображением памяти, который не освобождается?

Мы используем файлы с отображением памяти, поэтому я сосредоточусь на них.

ИЗМЕНИТЬ 4:

Я думаю, что я отследил проблему до исключения, которое происходит следующим образом:

java.lang.OutOfMemoryError
    at java.util.zip.Deflater.init(Native Method)
    at java.util.zip.Deflater.<init>(Unknown Source)
    at java.util.zip.Deflater.<init>(Unknown Source)
    at java.util.zip.DeflaterOutputStream.<init>(Unknown Source)
    at java.util.zip.DeflaterOutputStream.<init>(Unknown Source)
    at ....

В какой-то очень небольшой горстке потоков (сейчас у меня есть 4 примера) мы сбрасываем, что происходит выше. И когда это происходит, VMMap пикивает кучу процесса (а не кучу JVM, но фактическую собственную кучу) до 2 ГБ. Как только это произойдет, все развалится. Это теперь очень повторяемо (запуск того же потока в deflater приводит к появлению памяти)

Итак, возможно, мы смотрим на проблему с библиотекой zip JRE? Кажется сумасшедшим думать, что это будет, но я действительно в недоумении.

Если я возьму тот же поток и запустил его в другой системе (даже с тем же JRE - 32 бит, Java 7u45), мы не получим проблему. Я полностью удалил JRE и переустановил его без каких-либо изменений в поведении.

Ответы

Ответ 1

Наконец понял это.

Было несколько потоков данных, которые мы обработали (4 из 10 миллионов на этом сайте), которые завершили создание тонны объектов DeflaterOutputStream. Третья библиотека, которую мы использовали, вызывала функцию finish() в потоке вместо функции close(). Основной финализатор Deflater очищал вещи, поэтому, пока нагрузка не была слишком высокой, проблем не было. Но после переломного момента мы начали сталкиваться с этим:

http://jira.pentaho.com/browse/PRD-3211

что привело нас к этому:

http://bugs.sun.com/view_bug.do?bug_id=4797189

Спустя несколько часов система наконец-то попала в угол, из-за которого он не мог выбраться, и не смог создать собственный поток, когда нам было нужно.

Исправление заключалось в том, чтобы заставить стороннюю библиотеку закрыть DeflaterOutputStream.

Так определенно утечка собственного ресурса. Если кто-то еще что-то наносит такой эффект, инструмент VMMap был необходим для окончательного отслеживания того, какие потоки данных вызывают проблему.

Ответ 2

Я подозреваю, хотя явно трудно доказать, что вы столкнулись с проблемой 32-разрядного выделения памяти.

В потоках выделяется встроенная память, а не куча памяти, которая должна быть смежной, для запуска. Хотя я уверен, что WOW64 позволяет 32-битным процессам работать в области выше 4 гб, я не уверен в том, что я буду выделять собственную память для нового потока выше предела 4gb, если будет использоваться промежуточное пространство.

Следовательно, ваше приложение и куча находятся в lowish mem, другие процессы берут промежуточные 3.07gigs (если используется память), а затем пытаются выделить блок 4gb собственной памяти выше начального вызывающего абонента, чтобы создать новый поток.

Не могли бы вы подтвердить, что эта проблема возникает только при использовании памяти или над значком 4gb?