Volledige GC wordt zeer frequent

Ik heb een Java-webapp op één tomcat-exemplaar. Tijdens piekmomenten serveert de webapp ongeveer 30 pagina's per seconde en normaal rond de 15.

Mijn omgeving is:

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"

Na enkele uptime-dagen wordt de volledige GC vaker weergegeven en wordt dit een serieus probleem voor de beschikbaarheid van de toepassing. Na een herstart van een tomcat verdwijnt het probleem, maar keert natuurlijk terug na 5 tot 10 of 30 dagen (niet consistent).

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

Het toont een logboek vóór de herstart met een uptime van 6,6 dagen waar de app last van had omdat volledige GC 2,5 seconden nodig had en elke ~ 6 seconden gebeurde.

Vervolgens wordt een logboek weergegeven net na de herstart waarbij Volledige GC alleen elke 5-10 minuten is gebeurd.

Ik heb twee stortplaatsen met jmap -dump: format = b, file = dump.hprof PID toen de volledige GC's plaatsvonden (ik weet niet zeker of ik ze precies goed heb gekregen wanneer een volledige GC plaatsvond of tussen 2 Volledige GC's) en opende ze in http://www.eclipse.org/mat/ maar kreeg niets nuttigs in Leak Suspects:

  • 60 MB: 1 instantie van "org.hibernate.impl.SessionFactoryImpl" (ik gebruik slaapstand met ehcache)
  • 80MB: 1.024 instanties van "org.apache.tomcat.util.threads.ThreadWithAttributes" (dit zijn waarschijnlijk de 1024 werknemers van tomcat)
  • 45MB: 37 instanties van "net.sf.ehcache.store.compound.impl.MemoryOnlyStore" (dit zouden mijn ~ 37 cache-regio's in ehcache moeten zijn)

Merk op dat ik nooit een OutOfMemoryError krijg.

Om het even welke ideeën over waar zou ik volgende moeten kijken?

11
Veel nieuwe en afgedankte objecten.
toegevoegd de auteur Thorbjørn Ravn Andersen, de bron
een volledige GC op een grotere heap zou langer duren omdat er meer spullen te verzamelen zijn, maar experimenteren met grotere waarden van de maximale heapgrootte zou kunnen aangeven of je app in het algemeen meer ruimte nodig heeft.
toegevoegd de auteur matt b, de bron
toegevoegd de auteur matt b, de bron
Als u 16 gb RAM op de server hebt, waarom gebruikt u dan geen grotere maximale heapgrootte (-Xmx)?
toegevoegd de auteur matt b, de bron
"Ik heb nooit een OutOfMemoryError" gekregen - niet alles het geheugen wordt gebruikt maar de volledige GC treedt op omdat de oude generatie vol is. Door meer geheugen toe te wijzen, blijven objecten in het jonge gen langer behouden - meer kans om gereinigd te worden door een minder belangrijke verzameling/minder kans om gepromoot te worden.
toegevoegd de auteur symcbean, de bron
Kun je het gedrag reproduceren in een testomgeving? Misschien met wat belastingtesten. Ik heb eerder gedrag als dit gezuiverd, maar meestal met VEEL hulp van een profiler (die je server zal doden in een productie-omgeving).
toegevoegd de auteur pcalcao, de bron
@symcbean: is logisch. Zal proberen de hoop te vergroten en opnieuw evalueren.
toegevoegd de auteur cherouvim, de bron
@matt b: dat loste het op. Plaats het als een antwoord zodat ik het kan accepteren.
toegevoegd de auteur cherouvim, de bron
@svaor: Ik zal even kijken. Klinkt handig. bedankt!
toegevoegd de auteur cherouvim, de bron
@matt b: ik probeer de volgende keer 2GB's en kijk wat er gebeurt.
toegevoegd de auteur cherouvim, de bron
@ pcalcao: ik heb dat in het verleden gedaan, maar het is niet consistent. Bij volgasstresstests met JMeter had ik dit eenmaal op 6 dagen en een andere keer na 20 dagen (!).
toegevoegd de auteur cherouvim, de bron
Ik heb nooit een OutOfMemoryError gekregen, dus ik dacht dat omdat de toepassing kan worden uitgevoerd, het goed is. Ook heb ik gelezen dat het geven van te veel geheugen aan de JVM de volledige GC langzamer maakt. Is dat waar?
toegevoegd de auteur cherouvim, de bron
Zoals ik me herinner, kan eclipse-mat twee dumps van één JVM-sessie vergelijken. Dit kan u het verschil in situatie tonen wanneer een probleem nog niet bestaat en een situatie met vaak volledige GC's.
toegevoegd de auteur svaor, de bron

4 antwoord

Toen we deze kwestie hadden, hebben we er uiteindelijk achter gekomen dat de jonge generatie te klein was. Hoewel we veel ram hadden gegeven, kreeg de jonge generatie geen eerlijk aandeel.

Dit betekende dat kleine garbagecollecties vaker zouden voorkomen en ervoor zorgden dat sommige jonge objecten naar de vaste generatie werden verplaatst, wat ook betekent dat er meer grote garbagecollecties zijn.

Probeer de -XX: NewRatio te gebruiken met een vrij lage waarde (zeg 2 of 3) en kijk of dit helpt.

Meer informatie vindt u hier .

6
toegevoegd

Ik ben overgeschakeld van -Xmx1024m naar -Xmx2048m en het probleem is verdwenen. Ik heb nu 100 dagen bedrijfstijd.

4
toegevoegd

Wat er in jouw geval kan gebeuren, is dat je veel objecten hebt die iets langer leven dan de levenscyclus van NewGen. Als de ruimte voor overlevenden te klein is, gaan ze rechtstreeks naar de OldGen. -XX: + PrintTenuringDistribution kan enig inzicht verschaffen. Je NewGen is groot genoeg, dus probeer SurvivorRatio te verkleinen.

ook zal jconsole waarschijnlijk meer visueel inzicht verschaffen in wat er met je geheugen gebeurt, probeer het.

3
toegevoegd

Naast het afstemmen van de verschillende opties van JVM zou ik ook aanraden om te upgraden naar een nieuwere versie van de VM, omdat latere versies een veel beter afgestemde garbage collector hebben (ook zonder de nieuwe experimentele uit te proberen).

Afgezien daarvan, ook als het (gedeeltelijk) waar is dat het toewijzen van meer RAM aan JVM de tijd die nodig is om GC uit te voeren kan vergroten, is er een afweging tussen het gebruik van de volledige 16 GB geheugen en het vergroten van je geheugenbezetting, zodat je kunt proberen alle waarden te verdubbelen, beginnen

Xms1024m -Xmx2048m -XX: PermSize = 256m -XX: MaxPermSize = 512m

vriendelijke groeten

Massimo

2
toegevoegd
OK, zal JVM ook updaten. Bedankt.
toegevoegd de auteur cherouvim, de bron
Ja, de logs tonen een PSPermGen van ongeveer ~ 64MB, wat naar mijn mening de totale geladen klassengrootte is van: JVM, tomcat, bibliotheken en mijn app. Rechts?
toegevoegd de auteur cherouvim, de bron
Ik zal het proberen. Maar is maxperm 512 niet een beetje te veel? De tomcat-instantie voert slechts 1 toepassing uit met ongeveer 40 permanente (winterslaap) entiteiten en geen veerraamwerk. Er vindt geen herdistributie plaats op deze tomcat, alleen afsluiten/opstarten.
toegevoegd de auteur cherouvim, de bron
Zou kunnen zijn, mijn voorgestelde parameters waren slechts een eenvoudige schatting. Ik zou willen wijzen op het updaten van JVM als een betere zaak om te proberen, we hadden vergelijkbare problemen (en ook andere) en ze gingen weg toen we Java update om te updaten. 27. Laatste is update 29 maar we hadden wat problemen ermee.
toegevoegd de auteur user1133275, de bron