Повний GC стає дуже часто

У мене є веб-програма з Java, яка працює на одному екземплярі tomcat. Під час піків веб-програма обслуговує близько 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"

Після декількох днів безперебійної роботи повноцінний GC починає відбуватися частіше, і це стає серйозною проблемою для наявності програми. Після перезавантаження комахи проблема зникає, але, звичайно, повертається через 5-10 днів або 30 днів (не відповідає).

The Full GC log before and after a restart is at http://pastebin.com/raw.php?i=4NtkNXmi

Він показує журнал перед перезавантаженням у робочий час 6,6 днів, коли додаток страждає, тому що для повного GC потрібно 2,5 секунди, і це відбувалося кожні ~ 6 сек.

Потім він показує журнал тільки після перезавантаження, де Повний GC трапляється лише кожні 5-10 хвилин.

У мене є два звалища, коли використовується jmap -dump: format = b, file = dump.hprof PID , коли повні GCs, де відбувається (я не впевнений, чи отримав я їх точно, коли Full GC відбувався або між 2 повними GC) і відкрив їх у http://www.eclipse.org/mat/, але нічого корисного не знайшов у Leak Suspects:

  • 60 Мб: 1 примірник "org.hibernate.impl.SessionFactoryImpl" (я використовую сплячий режим з ehcache)
  • 80 Мб: 1024 екземплярів "org.apache.tomcat.util.threads.ThreadWithAttributes" (це, мабуть, 1024 працівники з томатної кошки)
  • 45 Мб: 37 примірників "net.sf.ehcache.store.compound.impl.MemoryOnlyStore" (вони повинні бути моїми ~ 37 областями кешування в ehcache)

Зауважте, що я ніколи не отримую OutOfMemoryError.

Будь-які ідеї щодо того, де я повинен виглядати далі?

11
Багато нових і відкинутих об'єктів.
додано Автор Thorbjørn Ravn Andersen, джерело
добре, повноцінний ГК на більшій купі займе більше часу, тому що є більше речовин для збирання, але експерименти з більшими значеннями розміру максимуму купу можуть показувати, якщо ваш додаток просто потребує більшого місця в цілому.
додано Автор matt b, джерело
також @cherouvim ви бачили oracle.com/technetwork/ java/javase/gc-tuning-6-140523.html ? може бути корисним.
додано Автор matt b, джерело
Якщо у вас є 16 ГБ оперативної пам'яті на сервері, чому не використовується більший розмір максимального розміру (-Xmx)?
додано Автор matt b, джерело
"Я не отримав OutOfMemoryError" - не всі пам'ять використовується, але повний GC відбувається, оскільки старе покоління заповнено. Виділяючи більше пам'яті, ви будете зберігати об'єкти в молодому гене у більшій мірі - більш імовірно, що вони очистяться від неповнолітньої колекції/менш імовірно, щоб їх рекламували.
додано Автор symcbean, джерело
Чи можете ви відтворити поведінку в середовищі тестування? Можливо, з деякими тестами на навантаження. Я налагодив таку поведінку, як це було раніше, але, як правило, використовуючи ОСІБ допомогу з профілятора (який вбиває ваш сервер у виробничому середовищі).
додано Автор pcalcao, джерело
@symcbean: має сенс Спробуйте збільшити купу та переоцінити.
додано Автор cherouvim, джерело
@matt b: це вирішило. Поділіть його як відповідь, щоб я міг прийняти.
додано Автор cherouvim, джерело
@svaor: я маю погляд. Звуки корисні. Дякую!
додано Автор cherouvim, джерело
@matt b: я спробую 2 ГБ наступного разу і подивіться, що станеться.
додано Автор cherouvim, джерело
@pcalcao: Я зробив це в минулому, але це не відповідає. При повному дросельному стрес-тесті з JMeter я мав це відбуватися раз на 6 днів, а інший раз - на 20 днів (!).
додано Автор cherouvim, джерело
Я ніколи не отримав OutOfMemoryError, тому я думав, що оскільки програма може працювати, це нормально. Також я прочитав, що надання JVM занадто багато пам'яті призведе до повільного повного GC. Це правда?
додано Автор cherouvim, джерело
Як я пам'ятаю, Eclipse-mat може порівнювати два звалища одного сеансу JVM. Це може показати вам різницю в ситуації, коли питання ще не існувало, і ситуація з часто повними ГД.
додано Автор svaor, джерело

4 Відповіді

Коли ми мали цю проблему, ми зрештою відстежили це, щоб молода генерація була занадто мала. Хоча ми дали багато барана, молодому поколінню не дали справедливої ​​частки.

Це означало, що невеликі колекції сміття траплялися частіше, і через те, що деякі молоді об'єкти були перенесені в орендоване покоління, це також означає більше великих сміттєвих колекцій.

Спробуйте використати -XX: NewRatio з досить низьким значенням (скажімо 2 або 3) і подивіться, чи це допомагає.

Більше інформації можна знайти тут .

6
додано

Я перейшов з -Xmx1024m на -Xmx2048m , і проблема залишилася. Тепер у мене 100 днів безвідмовної роботи.

4
додано

Що може статися у вашому випадку, це те, що у вас є багато об'єктів, які живуть трохи довше, ніж життєвий цикл NewGen. Якщо кількість людей, що вижили, занадто мала, вони прямують до OldGen. -XX: + PrintTenuringDistribution може надати деяку інформацію. Ваш NewGen досить великий, тому спробуйте зменшити SurvivorRatio .

Крім того, jconsole, ймовірно, забезпечить більш візуальне уявлення про те, що відбувається з вашою пам'яттю, спробуйте це.

3
додано

Окрім настроювання різних варіантів JVM, я також запропонував оновити його до нової версії VM, оскільки пізніші версії мають набагато краще настроєний сміттєвий збирач (також без спроб нового експериментального).

Крім того, якщо це (частково) правда, що призначення більшої кількості ОЗУ для JVM може збільшити час, необхідний для виконання GC, є компромісна точка між використанням всього 16 ГБ пам'яті та збільшенням зайнятості вашої пам'яті, тож ви можете спробувати подвоїти всі значення, починати

Xms1024m -Xmx2048m -XX: ПермСіз = 256м -XX: MaxPermSize = 512м

З повагою

Массимо

2
додано
Гаразд, також оновить JVM. Дякую.
додано Автор cherouvim, джерело
Так, журнали показують, що PSPermGen становить ~ 64 МБ, що я думаю, це загальний завантажений розмір класу: JVM, tomcat, бібліотеки та моє додаток. Правильно?
додано Автор cherouvim, джерело
Я спробую. Але хіба не maxperm 512 трохи забагато? У прикладі tomcat працює лише 1 прикладна програма з близько 40 стійкими (hibernate) об'єктами і не має весняних схем. Немає перерозподілів на цьому жорсткому диску, тільки при вимкненні/запуску.
додано Автор cherouvim, джерело
Може бути, мої запропоновані параметри були просто простою умовою. Я хотів би вказати на оновлення JVM як краще, щоб спробувати, у нас були подібні проблеми (а також інші), і вони пішли, коли ми оновили Java, щоб оновити 27. Останнє оновлення 29, але у нас були деякі проблеми.
додано Автор user1133275, джерело
ІТ КПІ - Java
ІТ КПІ - Java
436 учасників