У меня есть Java webapp, работающий на одном экземпляре tomcat. Во время пиков webapp обслуживает около 30 страниц в секунду и обычно около 15.
Моя среда:
O/S: SUSE Linux Enterprise Server 10 (x86_64)
RAM: 16GB
server: Tomcat 6.0.20
JVM: Java HotSpot(TM) 64-Bit Server VM 1.6.0_14
JVM options:
CATALINA_OPTS="-Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m
-XX:+UseParallelGC
-Djava.awt.headless=true
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
JAVA_OPTS="-server"
Спустя пару дней работоспособности Full GC начинает происходить чаще, и это становится серьезной проблемой для доступности приложения. После перезагрузки tomcat проблема исчезает, но, конечно, возвращается через 5-10 или 30 дней (несовместимо).
The Full GC log before and after a restart is at http://pastebin.com/raw.php?i=4NtkNXmi
Он показывает журнал перед перезагрузкой в течение 6,6 дней, когда приложение страдает, потому что Full GC требуется 2,5 секунды и происходит каждые 6 секунд.
Затем он показывает журнал сразу после перезагрузки, где Full GC происходит только каждые 5-10 минут.
У меня есть две дампы, использующие jmap -dump: format = b, file = dump.hprof PID
, когда появляются полные GC (я не уверен, правильно ли я получил их, когда Full GC происходил или между 2 полными GC) и открывал их в http://www.eclipse.org/mat/, но не получил ничего полезного в подозреваемых в утечке:
Обратите внимание: я никогда не получаю OutOfMemoryError.
Любые идеи о том, где я должен смотреть дальше?
Когда у нас была эта проблема, мы в конечном итоге отследили ее, чтобы молодое поколение было слишком маленьким. Несмотря на то, что мы дали много бара, молодому поколению не дали его справедливого вознаграждения.
Это означало, что небольшие сборки мусора случались бы чаще и приводили к тому, что некоторые молодые объекты были перемещены в поколение, что означало бы более крупные сборки мусора.
Попробуйте использовать -XX: NewRatio
с довольно низким значением (скажем, 2 или 3) и посмотрите, поможет ли это.
Более подробную информацию можно найти здесь .
Что может произойти в вашем случае, так это то, что у вас много объектов, которые живут немного дольше, чем жизненный цикл NewGen. Если пространство для оставшихся в живых слишком мало, они идут прямо к OldGen. -XX: + PrintTenuringDistribution
может дать некоторое представление. Ваш NewGen достаточно велик, поэтому попробуйте уменьшить SurvivorRatio
.
Кроме того, jconsole, вероятно, обеспечит более полное представление о том, что происходит с вашей памятью, попробуйте.
Помимо настройки различных опций JVM, я также предлагаю перейти на более новую версию VM, потому что в более поздних версиях есть намного лучше настроенный сборщик мусора (также без попытки нового экспериментального).
Кроме того, если это (частично) верно, что назначение большего количества бара для JVM может увеличить время, необходимое для выполнения GC, есть точка компромисса между использованием всего 16 ГБ памяти и увеличением вашей памяти, поэтому вы можете попробовать удвоить все значения, начать
Xms1024m -Xmx2048m -XX: PermSize = 256 м -XX: MaxPermSize = 512 м
С уважением
Massimo