2013-03-26 13 views
8

Ich bin auf der Suche nach Benchmarks, wie etwas funktioniert, während mit einer hohen Anzahl von laufenden Garbage Collection zu kämpfen. Ich habe zuvor einen Benchmark-Test durchgeführt, wie es sich in einem stabilen Single-Thread-Lauf verhält, und ich möchte jetzt die gleichen Tests in einer stressgeladeneren JVM durchführen. im Wesentlichen würde ich gerne Hintergrundfäden haben, die Objekte in einem ziemlich konstanten Tempo erstellen und zerstören.Techniken für konsistente GC Churn

Ich bin auf der Suche nach Vorschlägen, wie Sie eine stabile und dennoch GC-intensive Operation implementieren können. Es muss mehrere Ziele erreichen:

  • Verbringen Sie einen angemessenen Betrag (etwa 20-50%) der Zeit in GC
  • eine annähernd gleichbleib Menge an Arbeit im Laufe der Zeit tun, und erstellen Sie eine ähnlich konsistente Menge an Arbeit für die GC
  • vermeiden Sie den Heap überschwemmen und das Auslösen eines Java heap space Fehler
  • vermeiden Sie die GC und das Auslösen einer GC overhead limit exceeded Fehler Überlastung
+0

Danke, Stack-Überlauf braucht mehr von dir. –

Antwort

11

ich meine eigenen Pass ein umgesetzt t etwas, das eine stabile Menge an Speicherbereinigung verursachen könnte. Der vollständige Code ist hier verfügbar: https://bitbucket.org/snippets/dimo414/argzK

Das Fleisch Diese beiden Verfahren sind, das Konstrukt und setzt eine große Anzahl von Objekten in einem bestimmten Zeitraum von Echtzeit (im Gegensatz Zeit oder CPU-Zeit-Gewinde):

/** 
* Loops over a map of lists, adding and removing elements rapidly 
* in order to cause GC, for runFor seconds, or until the thread is 
* terminated. 
*/ 
@Override 
public void run() { 
    HashMap<String,ArrayList<String>> map = new HashMap<>(); 

    long stop = System.currentTimeMillis() + 1000l * runFor; 
    while(runFor == 0 || System.currentTimeMillis() < stop) { 
     churn(map); 
    } 
} 

/** 
* Three steps to churn the garbage collector: 
* 1. Remove churn% of keys from the map 
* 2. Remove churn% of strings from the lists in the map 
*  Fill lists back up to size 
* 3. Fill map back up to size 
* @param map 
*/ 
protected void churn(Map<String,ArrayList<String>> map) { 
    removeKeys(map); 
    churnValues(map); 
    addKeys(map); 
} 

Die Klasse implementiert Runnable, so dass Sie es (oder mehrere gleichzeitig) in einem eigenen Hintergrundthread starten können. Es wird so lange ausgeführt, wie Sie es angeben, oder wenn Sie es vorziehen, können Sie es als Daemon-Thread starten (damit es die JVM nicht stoppt) und es für immer als 0 Sekunden als Konstruktorargument angeben.


habe ich einige Benchmarking dieser Klasse und fand es in der Nähe ein Drittel seiner Zeit (vermutlich auf GC) und identifiziert ungefähre optimale Werte von 15-25% Churn und einer Größe von ~ 500 blockiert ausgegeben. Jeder Lauf wurde 60 Sekunden lang ausgeführt, und die folgenden Graphiken zeigen die Thread-Zeit, wie sie von java.lang.managment.ThreadMXBean.getThreadCpuTime() gemeldet wird, und die Gesamtzahl der Bytes, die vom Thread zugewiesen wurden, wie von com.sun.management.ThreadMXBean.getThreadAllocatedBytes() berichtet. fast 100% seiner Zeit im Thread

Churn Percentage benchmark

Die Kontrolle (0% Churn) sollten im Wesentlichen alle GC nicht vorstellen, und wir können es kaum ordnet Objekte und verbringt sehen. Von 5% bis zu 95% Abwanderung sehen wir ziemlich konstant etwa zwei Drittel der Zeit, die wir in Thread verbringen, vermutlich wird das andere Drittel in GC verbracht. Ein vernünftiger Prozentsatz, würde ich sagen. Interessanterweise sehen wir am sehr hohen Ende des Abwanderungsanteils mehr Zeit im Thread, vermutlich weil der GC so viel aufräumt, dass er tatsächlich effizienter sein kann. Es scheint ungefähr 20% ist eine gute Anzahl von Objekten, um jeden Zyklus zu schüren.

Data size benchmark

Dies zeichnet, wie die Gewinde Funktionen bei verschiedenen Zielgrößen für die Karte und Listen, wir hätten mehr Zeit als die Größe zunimmt sehen können, müssen in GC ausgegeben werden, und interessanterweise tatsächlich weniger Objekte Zuteilung wir am Ende, Da die Datenmenge größer ist, können im selben Zeitraum nicht so viele Schleifen erstellt werden. Da wir daran interessiert sind, die Menge an GC-Churn zu optimieren, mit der sich die JVM befassen muss, möchten wir, dass sie mit so vielen Objekten wie möglich umgehen und so wenig Zeit wie möglich im Arbeits-Thread verbringen muss.Es scheint also ungefähr 4-500 eine gute Zielgröße zu sein, da es eine große Anzahl von Objekten erzeugt und eine gewisse Zeit in GC verbringt.

Alle diese Tests wurden mit den Standardeinstellungen java durchgeführt, daher kann das Spielen mit dem Heap unterschiedliches Verhalten verursachen - insbesondere ~ 2000 war die maximale Größe, die ich setzen konnte, bevor der Heap voll wurde bessere Ergebnisse bei einer größeren Größe, wenn wir die Größe des Heap erhöhen.

+1

scheint legitim: D. –