2013-03-26 12 views
8

Czekam na porównanie, jak coś działa podczas rywalizacji z dużą ilością trwającego zbierania śmieci. Poprzednio sprawdzałem, jak zachowuje się w stabilnym, jednoniciowym biegu, a teraz chciałbym wykonać te same testy w bardziej obciążonej maszynie JVM; zasadniczo chciałbym, aby wątki w tle tworzyły i niszczały obiekty w rozsądnie spójnym tempie.Techniki powodujące konsekwentne GC Churn

Szukam wskazówek, jak wdrożyć stabilną, ale intensywną GC. To musi osiągnąć kilka celów:

  • spędzić przyzwoitą kwotę (powiedzmy 20-50%) czasu w GC
  • Czy w przybliżeniu stałą ilość pracy w czasie i tworzą spójną podobnie ilość pracy dla GC
  • Unikać zalewa sterty i wyzwalania błędu Java heap space
  • uniknąć przeciążenia GC i wyzwoleniem GC overhead limit exceeded błąd
+0

Dziękuję, przepełnienie stosu potrzebuje więcej od ciebie. –

Odpowiedz

11

i wdrożone moje własne zdać t coś, co może spowodować stałą ilość zbierania śmieci. Pełny kod jest tutaj: https://bitbucket.org/snippets/dimo414/argzK

Mięso jest te dwie metody, które konstrukt uwalniają wiele obiektów dla danego okresu czasu rzeczywistego (w przeciwieństwie do nici czasu lub czasu CPU):

/** 
* 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); 
} 

Ta klasa implementuje , więc możesz ją uruchomić (lub kilka naraz) w swoim wątku w tle. Będzie działał tak długo, jak go określisz, lub jeśli wolisz, możesz uruchomić go jako wątek demona (aby nie przerywał kończenia JVM) i określić, aby był uruchamiany na zawsze z 0 sekundami jako argument konstruktora.


zrobiłem kilka badań porównawczych tej klasy i okazało się, że spędził blisko trzecią część blokującą (przypuszczalnie na GC) swojego czasu i określonych przybliżonych optymalnych wartości 15-25% rezygnacji i wielkości ~ 500. Każdy przebieg był wykonywany przez 60 sekund, a poniższe wykresy narysowały czas gwintowania, zgodnie z raportem java.lang.managment.ThreadMXBean.getThreadCpuTime() i całkowitą liczbą bajtów przydzielonych przez wątek, zgłoszoną przez com.sun.management.ThreadMXBean.getThreadAllocatedBytes().

Churn Percentage benchmark

kontroli (0% rezygnacji) nie powinien wprowadzać żadnych GC zasadzie, można to zobaczyć przydziela prawie żadnych przedmiotów spędza prawie 100% czasu w wątku. Od 5% do 95% rezygnacji widzimy dość konsekwentnie około dwóch trzecich czasu spędzonego w wątku, prawdopodobnie druga trzecia jest spędzana w GC. Rozsądny procent, powiedziałbym. Co ciekawe, na bardzo wysokim końcu procentu rezygnacji widzimy więcej czasu spędzonego w wątku, prawdopodobnie dlatego, że GC tak bardzo się sprząta, że ​​faktycznie jest bardziej wydajny. Wygląda na to, że około 20% to duża liczba obiektów, które należy poddawać każdemu cyklowi.

Data size benchmark

tej działek jak funkcjonuje gwintowe w różnych rozmiarach docelowych na mapie i listach, widzimy jak rośnie wielkość więcej czasu muszą być wydawane w GC, i co ciekawe, że faktycznie kończy się przydzielenie mniejszej liczby przedmiotów, ponieważ większy rozmiar danych oznacza, że ​​nie można wykonać tylu pętli w tym samym okresie czasu. Ponieważ zależy nam na optymalizacji ilości odchodów GC, z którymi ma do czynienia JVM, chcemy, aby zajmowało się tylu obiektów, ile to możliwe, i spędzać jak najmniej czasu w wątku roboczym.Wydaje się, że około 4-500 to dobry rozmiar docelowy, ponieważ generuje dużą liczbę obiektów i spędza dużo czasu w GC.

Wszystkie te testy zostały wykonane standardowymi ustawieniami java, więc gra z stertą może powodować różne zachowanie - w szczególności ~ 2000 był maksymalnym rozmiarem, jaki mogłem ustawić, zanim sterty wypełniły się, możliwe, że zobaczymy lepsze wyniki w większym rozmiarze, jeśli zwiększyliśmy rozmiar sterty.

+1

wydaje się być uzasadnione: D. –