Запутанный профиль памяти Tomcat Persistent Session - PullRequest
6 голосов
/ 18 ноября 2011

Как и в случае любой проблемы с управлением памятью, это длинная история, так что запутайтесь.

У нас есть приложение, которое страдает от некоторых проблем управления памятью, поэтому я пытался профилировать приложение, чтобы понять, в чем проблема. Сегодня я видел эту тему сегодня:

Исключение из сеанса Tomcat для предотвращения ошибки OutOfMemoryEr

... что похоже на то, что я видел в профилировщике. По сути, если бы я ударил приложение с группой пользователей с помощью Jmeter, оно бы долго удерживало память в куче, в конце концов, пока сессии не начали истекать. Однако, в отличие от плаката в этой теме, у меня есть источник и возможность попробовать реализовать сеансы постоянного состояния с Tomcat, что я и пытался сделать сегодня, с ограниченным успехом. Я думаю, что это некоторые настройки конфигурации, которые мне не хватает. Вот что у меня есть в context.xml:

  <Manager className='org.apache.catalina.session.PersistentManager'
                saveOnRestart='false'
                maxActiveSessions='5'
                minIdelSwap='0'
                maxIdleSwap='1'
                maxInactiveInterval='600'
                maxIdleBackup='0'>
   <Store className='org.apache.catalina.session.FileStore'/>
   </Manager>

И в web.xml у меня есть это:

<session-config>
    <session-timeout>
        10
    </session-timeout>
</session-config>

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

enter image description here

Как вы можете видеть на картинке, я поместил некоторые аннотации. Это часть, обведенная вокруг вопросительного знака, которую я действительно не понимаю больше всего на свете. Вы можете видеть, что я использую кнопку «Выполнить сборку» на Jconsole в нескольких разных точках, и вы можете увидеть часть диаграммы, где я запускаю приложение со многими клиентами с Jmeter.

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

Или это простой сценарий утечки памяти? Ранее сегодня я взял дамп кучи и загрузил его в инструмент Eclipse Memory Analyzer, использовал функцию «Обнаружение утечки», и все, что он сделал, это подтвердил теорию о том, что это проблема размера сеанса; единственная обнаруженная утечка была в java.util.concurrent.ConcurrentHashMap $ Segment, которая привела меня к этой теме Память, полностью используемая Java ConcurrentHashMap (под Tomcat)

, что заставляет меня думать, что это не приложение, которое на самом деле утечка.

Другие соответствующие данные: - Запуск / тестирование этого на моей локальной машине в настоящее время. Вот откуда все эти результаты. - Использование Tomcat 6 - Это приложение JSF2.0 - Я добавил системное свойство -Dorg.apache.catalina.STRICT_SERVLET_COMPLIANCE = true согласно документации Tomcat

Итак, я думаю, здесь есть несколько вопросов: 1. Я правильно настроил? 2. Есть ли утечка памяти? 3. Что происходит в этом профиле памяти? 4. Это (относительно) нормально?

Заранее спасибо.

UPDATE

Итак, я попробовал советы Шона и нашел несколько новых интересных вещей.

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

1) Поразите приложение несколькими десятками клиентов, просто посетив простую страницу. Я отметил, что все сеансы были освобождены, как и ожидалось, после указанного ограничения по времени, и память была освобождена. Та же самая вещь отлично работает с тривиальным числом клиентов, для сложного случая, попав на «большую» страницу.

2) Затем я попытался запустить приложение со сложным сценарием использования с несколькими десятками клиентов. На этот раз было начато на несколько десятков больше сеансов, чем ожидалось. Казалось, что каждый клиент инициировал от одного до трех сеансов. По истечении времени истечения сеанса освободилось немного памяти, но, по словам слушателя сеанса, только около трети сеансов было уничтожено. Несмотря на это, папка, которая на самом деле содержит данные сессий, пуста. Большая часть памяти, которая была использована, также сохраняется. Но после ровно одного часа работы стресс-теста сборщик мусора запускается, и все возвращается в нормальное состояние.

Итак, дополнительные вопросы включают в себя:

1) Почему сеансы могут обрабатываться должным образом в простом случае, но когда вещи становятся интенсивными, они перестают правильно управляться? Обработчик сеанса искажает информацию, или JMeter как-то влияет на это?

2) Почему сборщик мусора ждет один час, чтобы запустить? Существует ли системный параметр, который требует, чтобы сборщик мусора ДОЛЖЕН работать в течение определенного периода времени, или если какой-то параметр конфигурации мне не хватает?

Еще раз спасибо за постоянную поддержку.

ОБНОВЛЕНИЕ 2

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

Ответы [ 2 ]

5 голосов
/ 18 ноября 2011

Позвольте мне попытаться ответить на вопросы как можно лучше

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

  2. Я не думаю, что есть утечка памяти.Инкрементальные GC запускаются.похоже, много памяти продвигается к старому поколению.Но как только ваше приложение сможет запустить полный сборщик мусора, память возвращается к нормальной жизни.Если вам нужно, чтобы в сеансах пользователей было много данных, хранящихся в них, память будет вашим компромиссом.До тех пор, пока вы уничтожаете данные, как только они выходят из системы / время ожидания, память должна быть в порядке в долгосрочной перспективе.Область вашего вопроса (???) будет серой областью, где ваши сеансы все еще активны, поэтому хранящиеся в них данные будут храниться, возможно, на этом этапе переведены в старое поколение.После того, как память переведена на Old Gen, ей нужен полный сборщик мусора для ее очистки.Нажатие на кнопку сделало это.Приложение в конечном итоге запланировало бы полный сбор данных.

  3. Я думаю, что # 2 помогает ответить на этот вопрос

  4. Конечно, это выглядит нормально для стресс-теста.Попробуйте запустить его снова, не нажимая кнопку Perform GC.Посмотрите, не исчезнет ли память сама по себе.Обратите внимание, что сборщик мусора выполнит полный сборщик мусора, когда почувствует, что должен это сделать.Для очистки старого поколения требуется приостановка, чтобы ГХ не выполнял это действие, если не считает, что у него недостаточно ресурсов для правильного управления приложением.

Несколько других вещей, которые вы можетехочу сделать для будущих тестов.Обратите внимание на использование кучи между молодым поколением и старым поколением кучи.Из скриншота видно, что выделено 872 Мб кучи, поэтому разбивка того, где находится память во время ваших нагрузочных тестов, поможет правильно определить, где хранится куча.

Аналогичным образом рассмотрите возможность включения подробного ведения журнала GC , чтобы вы могли получить отчет о разбивке кучи.Есть много инструментов, которые помогут вам составить график журнала GC, чтобы вам не приходилось читать журнал вручную.Это также может быть записано в файл (-Xloggc: file), если вы не хотите, чтобы его отправляли на стандартный вывод.

Если размер сеанса становится слишком большим для управления, вы можете разгрузить этот файл.память в другом месте.Можно привести несколько примеров: использовать BigMemory, DB Persistance или какой-либо другой способ уменьшения размеров сеанса.

0 голосов
/ 14 сентября 2012

Я не вижу, где кто-то указал на вашу опечатку:

minIdelSwap='0'

Не уверен, что это кому-то пригодится, но это, безусловно, приведет к тому, что PersistenceManager будет вести себя не так, как вы ожидаете.

...