2015-11-19 4 views
9

Nach mehreren Stunden, My HTTP-Server beginnen häufig Haupt-GC, aber kein Heap wurde freigegeben.häufige große gc aber nicht frei Heap?

mehrere Male später gc, promotion failed und concurrent mode failure aufgetreten, dann Heap wurde freigegeben. Mein gc Protokoll ist unten:

{Heap before GC invocations=7172 (full 720): 
par new generation total 737280K, used 667492K [0x000000076b800000, 0x000000079d800000, 0x000000079d800000) 
    eden space 655360K, 100% used [0x000000076b800000, 0x0000000793800000, 0x0000000793800000) 
    from space 81920K, 14% used [0x0000000793800000, 0x00000007943d91d0, 0x0000000798800000) 
    to space 81920K, 0% used [0x0000000798800000, 0x0000000798800000, 0x000000079d800000) 
concurrent mark-sweep generation total 1482752K, used 1479471K [0x000000079d800000, 0x00000007f8000000, 0x00000007f8000000) 
concurrent-mark-sweep perm gen total 131072K, used 58091K [0x00000007f8000000, 0x0000000800000000, 0x0000000800000000) 
2015-11-19T21:50:02.692+0800: 113963.532: [GC2015-11-19T21:50:02.692+0800: 113963.532: [ParNew (promotion failed) 
Desired survivor size 41943040 bytes, new threshold 15 (max 15) 
- age 1: 3826144 bytes, 3826144 total 
- age 2:  305696 bytes, 4131840 total 
- age 3:  181416 bytes, 4313256 total 
- age 4:  940632 bytes, 5253888 total 
- age 5:  88368 bytes, 5342256 total 
- age 6:  159840 bytes, 5502096 total 
- age 7:  733856 bytes, 6235952 total 
- age 8:  64712 bytes, 6300664 total 
- age 9:  314304 bytes, 6614968 total 
- age 10:  587160 bytes, 7202128 total 
- age 11:  38728 bytes, 7240856 total 
- age 12:  221160 bytes, 7462016 total 
- age 13:  648376 bytes, 8110392 total 
- age 14:  33296 bytes, 8143688 total 
- age 15:  380768 bytes, 8524456 total 
: 667492K->665908K(737280K), 0.7665810 secs]2015-11-19T21:50:03.459+0800: 113964.299: [CMS2015-11-19T21:50:05.161+0800: 113966.001: [CMS-concurrent-mark: 3.579/4.747 secs] [Times: user=13.41 sys=0.35, rea 
l=4.75 secs] 
(concurrent mode failure): 1479910K->44010K(1482752K), 4.7267420 secs] 2146964K->44010K(2220032K), [CMS Perm : 58091K->57795K(131072K)], 5.4939440 secs] [Times: user=9.07 sys=0.13, real=5.49 secs] 
Heap after GC invocations=7173 (full 721): 
par new generation total 737280K, used 0K [0x000000076b800000, 0x000000079d800000, 0x000000079d800000) 
    eden space 655360K, 0% used [0x000000076b800000, 0x000000076b800000, 0x0000000793800000) 
    from space 81920K, 0% used [0x0000000798800000, 0x0000000798800000, 0x000000079d800000) 
    to space 81920K, 0% used [0x0000000793800000, 0x0000000793800000, 0x0000000798800000) 
concurrent mark-sweep generation total 1482752K, used 44010K [0x000000079d800000, 0x00000007f8000000, 0x00000007f8000000) 
concurrent-mark-sweep perm gen total 131072K, used 57795K [0x00000007f8000000, 0x0000000800000000, 0x0000000800000000) 
} 

Es scheint, die CMS GC keinen Sinn machen. Könnten Sie mir bitte erklären?

Das ist mein gc config:

/usr/local/jdk1.7.0_79/bin/java 
-server 
-Xms2248m 
-Xmx2248m 
-Xmn800m 
-XX:PermSize=128m 
-XX:MaxPermSize=128m 
-XX:MaxTenuringThreshold=15 
-XX:+UseCMSCompactAtFullCollection 
-XX:CMSFullGCsBeforeCompaction=0 
-XX:+UseConcMarkSweepGC 
-XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps 
-XX:+PrintGCDateStamps 
-Xloggc:gc.log 
-XX:+PrintHeapAtGC 
-XX:+PrintTenuringDistribution 
-XX:+UseFastAccessorMethods 

UPDATE

Es gibt eine periodische Task seit dem Start des Servers ist. Sein Job ist Laden von Daten von MySQL und in jvm-Heap zu halten. Wenn eine Clientanforderung kommt, sollte der Server mit den Daten rechnen. Der Code der Aufgabe wie folgt aus:

private volatile List<ActivityInfo> activityInfos; 

public void run() { 
    activityInfos = db.loadActivity(); 
} 

public ActivityInfo getActivityByClient() { 
    // 
    List<ActivityInfo> local = activityInfos; 
    // biz code 
    ActivityInfo response = // biz code 
    return response; 
} 

// executor 
executor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.MINUTES); 

Was verwirrt mich am meisten Grund Heap nach der vollständigen gc befreit wurde, nicht nach großen gc?

UPDATE

full gc log is here

Antwort

4

Das würde bedeuten, dass Sie ganz in der Nähe Ihrer maximalen Heap-Größe laufen lassen, so gibt es häufige GCs aber sehr wenig befreit. Versuchen Sie es deutlich zu erhöhen, sagen wir 1,5x oder 2x.

+0

Ich verwechselte das, warum Heap wurde nach vollem gc freigegeben, nicht nach großen gc? – znlyj

+0

Err, weil der volle GC etwas freigab, das der HauptGC nicht erreichte? – EJP

+0

Die Heap-Nutzung nach einer großen Sammlung ist nur 44 MB, so dass der Heap bereits sehr großzügig bemessen ist und eine Erhöhung nicht helfen wird. –

3

Ihr Kinderzimmer Haufen gesetzt mit -Xmn800m aber der Kindergarten Heap-Nutzung nach der Sammlung 800MB ist nur 8 MB

- age 15: 380768 bytes, 8524456 total

So Ihre Anwendung eine lange Zeit nur Müll laufen können den Kindergarten Halde zu sammeln. Irgendwann wird sich der Tenure Heap füllen. Nach der Sammlung 7172 sind nur noch 3 MB übrig - der Unterschied zwischen den Gesamt- und den verwendeten Heap-Werten.

concurrent mark-sweep generation total 1482752K, used 1479471K

Der Garbage Collector hat zur Kenntnis genommen, dass die festen angestellten Haufen, um die Kapazität und eine gleichzeitige Markierung vor dem Start der Protokollaktivität ausgelöst worden sein geschrieben nahe ist. Während der Phase der gleichzeitigen Markierung werden Objekte weiterhin zugewiesen und der Nursery Heap füllt die Auslösung einer Kinderkrippe.

Wenn die Baumschule abgeholt wird, ist nicht mehr genug Platz auf dem Tenure-Heap, um die Objekte, die auf den Tenure-Heap befördert werden sollen, zu halten. Dies führt zu der promotion failed und der Müllsammler ist gezwungen, den gesamten Haufen zu verarbeiten, nicht nur die Gärtnerei. Wenn dies auftritt, bevor die gleichzeitige Markierungsphase abgeschlossen ist, wird auch eine concurrent mode failure protokolliert. Nach der vollständigen Sammlung sind 1,4 GB im Tenure-Heap. Diese

concurrent mark-sweep generation total 1482752K, used 44010K

ist die Art und Weise, dass die Dinge gemeint geschehen. Nursery-Sammlungen sind billig, wenn die meisten neuen Objekte schnell aus dem Rahmen fallen und die JVM wird das Kinderzimmer nur so lange sammeln, wie es nur geht. Schließlich füllt sich jedoch der Tenure-Heap und der teurere Full-GC wird benötigt.

Was würde passieren, wenn Sie die Baumschule reduzieren würden, sagen wir mal die Hälfte davon? Unter der Annahme, dass Ihre Anwendung Objekte mit einer konstanten Rate erstellt, würde die Gärtnerei in etwa der Hälfte der Zeit füllen. Da die Menge an Daten, die von der Anwendung verwendet werden, unabhängig von GC ist, würde die gleiche Anzahl von Objekten beibehalten und gefördert werden wie bei der größeren Baumschule. So würde sich auch die gesammelte Sammlung schneller füllen.

Mit der gleichen Gesamtgröße Heap jedoch. das feste Gebiet ist größer als vorher, so dass es mehr Kindergartenkollektionen braucht, um das feste Gebiet zu füllen, also gibt es Kompromisse. Eine gute Faustregel ist, die Baumschule auf ein Viertel der Größe des festgesetzten Bereichs zu dimensionieren.

UPDATE

Der vollständige gc.log ist aus einem anderen GC laufen, aber ich denke, dass das Anwendungsverhalten ähnlich ist. Darin sehe ich viele CMS: abort preclean due to time Nachrichten. Diese sind in Jon Masamitsu's Weblog beschrieben. Aus Gründen der Effizienz muss der CMS-Collector vor dem Stoppen aller ausführbaren Threads auf eine Nurseriesammlung zurückgreifen. Wenn eine solche Sammlung nicht innerhalb einer bestimmten Zeit stattfindet, wird die CMS-Sammlung abgebrochen.

Wenn die Anwendungslast niedrig ist, die Auslastung des Heapspeichers jedoch hoch ist, beginnt der CMS-Kollektor zu laufen und seine anfängliche Markierungsphase zu durchlaufen. Wenn eine Kinderkrippen-Sammlung nicht ausgeführt werden kann, wird die CMS-Sammlung abgebrochen. Dies kann mehrmals vorkommen. Dann kommt ein Baumschulhaufen und der Zyklus wiederholt sich. Dies wird fortgesetzt, bis entweder eine CMS- und eine Kinderkrippen-Sammlung zusammenfallen oder der Tenure-Heap vollständig gefüllt ist.

Da Objekte nur langsam zum Tenure-Heap hochgestuft werden, kann dieses Verhalten für einige Zeit bestehen bleiben. Hier dauert es vom 2015-11-24T00: 28: 23.921 bis 2015-11-24T01: 55: 52.461 - anderthalb Stunden. Während dieses Zeitraums wird Zeit vergeudet, indem eine anfängliche Markierung nur zum Abbrechen der Operation ausgeführt wird.

Es gibt eine Reihe von Möglichkeiten, dieses Verhalten zu beheben.

  • Die Größe des Kinderzimmers reduzieren. Dies wird die Rate der Kindergartenkollektionen erhöhen und sie werden öfter mit CMS-Sammlungen zusammenfallen. Allerdings scheint die große Baumschule gut zu funktionieren, und wenn sie reduziert wird, werden mehr CMS-Sammlungen mit schlechterer Leistung unter starker Belastung entstehen.
  • CMSMaxAbortablePrecleanTime erhöhen. Dies bedeutet, dass CMS vor dem Abbruch der Sammlung länger warten wird. Je länger jedoch die Wartezeit ist, desto teurer wird die CMS-Sammlung
  • Aktivieren Sie CMSScavengeBeforeRemark. Das ist meine Empfehlung. Dies wird eine Kinderkrippe zur richtigen Zeit erzwingen und die CMS-Sammlung wird niemals abgebrochen. Die Pausenzeit für die Bemerkungsphase wird länger sein, da auch eine Kinderkrippen-Sammlung stattfinden wird, aber da die zusätzliche Zeit gering und vollständige Sammlungen so selten sind, ist dies wahrscheinlich kein Problem.

Beachten Sie, dass der Baumschulhaufen manchmal die junge Generation und der festgebackene Haufen die alte Generation genannt wird. Weitere Informationen finden Sie aktuelle Understanding Garbage Collection oder Garbage Collection Basics

+0

Vielleicht sollte ich '-Xmn' kleiner einstellen? Was mich verwirrt ist, dass warum Heap wurde nach vollem GC freigegeben, nicht nach großen GC? – znlyj

+0

Ich habe die erste Frage mit einem Update auf meine Antwort angesprochen. Was die zweite betrifft, ist mir kein Unterschied zwischen "full" und "major" gcs bekannt. Was sagt Ihnen, dass große GCs aufgetreten sind? –

+0

Ich kann sagen, dass große GC durch GC Log aufgetreten sind. – znlyj

4

für die Lösung es, Sie Eclipse-Memory Analyzer verwenden können. Es zeigt Ihnen alle diese Speicher- und Thread-Probleme im Detail. Sie können auch jConsole dafür.

+0

Memory Analyzer ist ein großartiges Werkzeug, um den Inhalt Ihres Heaps zu untersuchen, aber zuletzt habe ich gesehen, dass es keine Möglichkeit gibt, GC-Logs oder die Performance der GC-Algorithmen zu untersuchen. –

Verwandte Themen