Проблема использования памяти Java / производительности пула потоков - PullRequest
4 голосов
/ 26 июля 2011

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

У меня есть серверное приложение, которое использует поток слушателя для прослушивания входящих данных. Поступающие данные интерпретируются в сообщения, специфичные для приложения, и эти сообщения затем вызывают события.

До этого момента я не имел никакого контроля над тем, как все делается.

Поскольку это унаследованное приложение, об этих событиях ранее заботился тот же поток слушателя (в основном однопоточное приложение). События отправляются в черный ящик, и появляется результат, который должен быть записан на диск.

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

Только с предыдущей настройкой и средством записи в фоновом режиме все работает нормально, а пропускная способность в ~ 1,6 раза больше, чем ранее.

Когда я добавляю пул потоков, производительность снижается. В начале все, кажется, работает гладко, но через некоторое время все очень медленно, и, наконец, я получаю OutOfMemoryExceptions. Странно то, что когда я печатаю количество активных потоков каждый раз, когда задача добавляется в пул (вместе с информацией о том, сколько задач поставлено в очередь и т. Д.), Это выглядит так, как будто у пула потоков нет проблем, не отставая от продюсер (ветка слушателя).

Используя top -H для проверки загрузки процессора, он с самого начала довольно равномерно распределяется, но в конце рабочие потоки едва активны и активен только поток слушателя. И все же, похоже, он не отправляет больше задач ...

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

Любые идеи приветствуются. Особенно идеи о том, как более эффективно диагностировать такую ​​ситуацию. Как я могу получить лучший профиль того, что делают мои темы и т. Д.

Спасибо.

Ответы [ 4 ]

5 голосов
/ 26 июля 2011

Замедление, а затем из памяти означает утечку памяти.

Поэтому я бы начал с использования некоторых инструментов анализатора памяти Java, чтобы определить, есть ли утечка и что происходит утечка.Иногда вам везет, и просочившийся объект хорошо известен, и становится совершенно ясно, кто цепляется за вещи, которые они не должны.

4 голосов
/ 27 июля 2011

Спасибо за ответы.Я прочитал о Java VisualVM и использовал его в качестве инструмента.Результаты и выводы подробно изложены ниже.Надеюсь, изображения будут работать достаточно долго.

Сначала я запустил программу и создал несколько дампов кучи, думая, что я могу просто проанализировать дампы и посмотреть, что занимает всю память.Это, вероятно, сработало бы, если бы файл дампа не стал настолько большим, и моя рабочая станция имела ограниченный доступ к нему.После двух часов ожидания одной операции я понял, что не могу этого сделать.

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

Оказывается, что при отправке сообщений с более медленной скоростью проблема нехватки памяти не возникает!График использования памяти приведен ниже.

медленная отправка http://img197.imageshack.us/img197/1628/slowsend.png

Пики - это результаты совокупного выделения памяти, а последующие впадины - после запуска сборщика мусора.Хотя объем использования памяти, безусловно, вызывает тревогу, и, вероятно, здесь есть проблемы, долгосрочная тенденция утечки памяти не наблюдается.

Я начал постепенно увеличивать скорость отправки сообщений в секунду, чтобы увидеть, гдеприложение попадает в стену.На рисунке ниже показан совершенно другой сценарий, чем предыдущий ...

быстрая отправка http://img200.imageshack.us/img200/151/fastsend.png

Поскольку это происходит при увеличении скорости отправки сообщений, я предполагаю, что мое освобождениеВ результате поток слушателя может очень быстро принимать множество сообщений, что вызывает все больше и больше выделений.Сборщик мусора не запускается, и использование памяти сталкивается со стеной.

Конечно, есть еще кое-что, но, учитывая то, что я узнал сегодня, у меня есть довольно хорошее представление о том, куда идти дальше.Конечно, любые дополнительные предложения / комментарии приветствуются.

Эти вопросы, вероятно, следует отнести к категории использования памяти, а не пулов потоков ... Пул потоков вообще не был проблемой.

2 голосов
/ 26 июля 2011

Я согласен с @djna.Работает пул потоков пакета java для параллелизма.Он не создает темы, если они не нужны.Вы видите, что количество потоков соответствует ожидаемому.Это означает, что, вероятно, что-то в вашем унаследованном коде не готово к многопоточности.Например, некоторый фрагмент кода не синхронизирован.В результате некоторый элемент не удаляется из коллекции.Или некоторые дополнительные элементы хранятся в коллекции.Таким образом, использование памяти растет.

Кстати, я не совсем понял, какая часть приложения сейчас использует пул потоков.Был ли у вас один поток, который обрабатывает события, и теперь у вас есть несколько потоков, которые делают это?Возможно, вы изменили механизм связи между потоками?Добавлены очереди?Это может быть еще одним направлением вашего расследования.

Удачи!

1 голос
/ 26 июля 2011

Как уже упоминал djna, это скорее всего утечка памяти. Я думаю, что вы где-то храните ссылку на запрос:

  • В потоке диспетчера, который ставит в очередь запросы
  • В темах, которые занимаются запросами
  • В черном ящике, обрабатывающем запросы
  • В потоке записи, который пишет на диск.

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

В соответствии с рекомендациями djna, вы можете использовать анализатор памяти Java, чтобы определить, где располагаются данные.

...