În acest articol, nu aș vrea să se concentreze pe principiul de funcționare al colectorului de gunoi - acest lucru este bine și clar descrise aici: habrahabr.ru/post/112676/. Vrei mai multe du-te la elementele de bază practice și caracteristicile cantitative pentru configurarea de colectare a gunoiului în JVM - și să încerce să înțeleagă modul în care aceasta poate fi caracteristicile effektivnym.Kolichestvennye GCRassmotrim să evalueze eficiența următorii parametri: Lățimea de bandă O măsură care determină capacitatea aplicației de a opera în sarcină de vârf, indiferent de pauze în timpul asamblare și răspunsul GC măsura timpul necesar dimensiunea memoriei care determină capacitatea aplicației de a face față fluctuațiilor numărului de opriri și munca folosind dimensiune GC emoy dimensiunea memoriei de memorie care este necesară pentru GC eficiente În general, aceste caracteristici sunt compromise și îmbunătățite una dintre ele conduce la restul costurilor. Pentru majoritatea aplicațiilor, toate cele trei caracteristici importante, dar de multe ori una sau două sunt mai importante pentru aplicarea - acest lucru va fi un punct de plecare pentru a configura.
Principiile de bază ale reglării GC Luați în considerare trei reguli de bază pentru înțelegerea setărilor GC:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
clasa publică MemoryConsumer implementează Runnable
statică definitivă privată int OBJECT_SIZE = 1024 × 1024; statică finală privată int OBJECTS_NUMBER = 8; definiție statică privată int ADD_PROCESS_TIME = 1000; statică finală privată int NUMBER_OF_REQUEST_THREADS = 50; statică finală privată lungă EXPERIMENT_TIME = 30000; static privat static boolean stop = false;
public static void principal (String [] args) aruncă InterruptedException
începe (); Necesar de răspuns (EXPERIMENT_TIME); stop ();>
privat static void () java -XX: + PrintGCTimeStamps -XX: + PrintGCDetails -verbose: gc -Xloggc: gc.log ru.skuptsov.MemoryConsumer întârziere și vâlcele sum gc.log: 0.167: [GC complet [PSYoungGen: 21792K → 13324K (152896K)] [PSOldGen: 341095K → 349363K (349568K)] 362888K → 362687K (502464K) [PSPermGen: 2581K → 2581K (21248K)], 0.0079385 secunde] [Times: user = 0.01 sys = 0,00, real = 0,01 secs] Unde reale = 0.01 secunde - timpul efectiv petrecut pe utilitate sborku.A poate fi utilizat VisualVM, un plug-in instalat VisualGC, care în mod clar se poate observa alocarea memoriei în diferite zone ale GC (Eden, Survivor1, Survivor2, vechi) și a vedea statisticile privind începutul și durata unei colectare a gunoiului. Determina dimensiunea necesară a memoriei la început, avem nevoie pentru a rula aplicația cu cea mai mare cantitate posibilă de memorie decât este, de fapt nevoie de aplicație. Dacă n-am ști inițial cât de mulți vor lua cererea noastră în memorie - puteți rula aplicația fără a specifica -Xmx și -Xms și HotSpot VM va selecta dimensiunea memoriei. Dacă la începutul cererii vom primi OutOfMemory (Java spațiu grămadă sau spațiu PermGen), atunci putem crește iterativ dimensiunea memoriei disponibile (-Xmx sau -XX: PermSize) până când eroarea nu este uydut.Sleduyuschim pas este de a calcula dimensiunea de viață lungă viu date - mărimea zonelor vechi și permanente ale grămezii, după o fază de colectare a gunoiului plin. Această dimensiune - cantitatea aproximativă de memorie necesară pentru funcționarea aplicației, să-l obțină, puteți vedea dimensiunea zonei după o serie de ansamblul complet. De obicei, dimensiunea memoriei necesare pentru aplicarea -Xms și -Xmx de 3-4 ori mai mult decât cantitatea de date vii. Deci, la jurnalul, cele de mai sus - vechea valoare a câmpului, după o fază de colectare a gunoiului plin - 349363K. Apoi valoarea sugerată este -Xmx și -Xms 1400 MB. -XX: PermSize și -XX: MaxPermSize este de 1,5 ori mai mare decât PermGenSize după faza completă de colectare a gunoiului - 13324K 20 MB. Dimensiunea generației tinere se presupune a fi de 1-1,5 din volumul datelor live 525 MB. Apoi, vom obține o rula JVM șir cu următorii parametri: java -Xms1400m -Xmx1400m -Xmn525m -XX: PermSize = 20m ru.skuptsov.MemoryConsumer În VisualVm obține următoarea imagine:
În doar 30 de secunde de experiment, s-au produs 54 de ansambluri - 31 mici și 23 complete - cu un timp total de oprire de 3.227c. Această întârziere nu poate satisface cerințele necesare - să vedem dacă putem îmbunătăți situația fără a modifica codul aplicației.
Setarea timpului de răspuns admisibil Următorii parametri trebuie să fie măsurate și luate în considerare la stabilirea timpului de răspuns: Măsurarea mici de colectare a gunoiului Durata Frecvența de măsurare a gunoiului de asamblare mică de măsurare a lungimii cel mai rău caz o colectare a gunoiului de frecvență de măsurare completă a cel mai rau caz un plin ajustări de colectare a gunoiului la tineri și bătrâni timpul de generare necesară pentru punerea în aplicare faza de colectare a gunoiului mici depinde de numărul de obiecte din generația tânără, mai mică dimensiunea sa - durata de jos, dar acest lucru crește porțiuni că, din cauza zona începe să se umple mai des. Încercați pentru a reduce timpul fiecărui ansamblu de mici, prin reducerea dimensiunii tinerei generații, menținând în același timp mărimea vechii generații. Aproximativ se poate estima că în fiecare secundă trebuie să clar în tânăra generație 50potokov 8obektov * * 1MB
400 Mbps. Rulați cu următorii parametri: java -Xms1275m -Xmx1275m -Xmn400m -XX: PermSize = 20m ru.skuptsov.MemoryConsumer În VisualVm obține imaginea de mai jos:
Timpul total de gunoi nu am fost în măsură să afecteze o mică acumulare - 1,533s - creșterea frecvenței de ansambluri mici, dar timpul total deteriorat - 3661 datorită faptului că a crescut rata de generare vechi și frecvența crescută de a apela o colecție completă de gunoi umple. Pentru a depăși acest lucru - încercați să măriți dimensiunea vechii generații - rulați jvm cu parametrii:
java -Xms1400m -Xmx1400m -Xmn400m -XX: PermSize = 20m en.skuptsov.MemoriaConsumer
Pauza totală sa îmbunătățit acum la 2.637 secunde, iar valoarea totală a memoriei necesare aplicației a fost redusă - astfel încât este posibil să se găsească echilibrul potrivit între generația veche și cea tânără pentru a distribui durata de viață a obiectelor într-o aplicație specifică.
Când timpul nu este încă mulțumit cu noi - puteți merge la colectorul de gunoi concurente, inclusiv opțiunea -XX: + UseConcMarkSweepGC - un algoritm care va încerca să efectueze lucrări de fond privind marcarea obiectelor de ștergere într-un flux separat, fluxurile de aplicații paralele.
Setarea gunoier simultană ConcMarkSweep GC necesită setări mai atentă - unul dintre obiectivele principale este de a reduce stop-lume pauze în absența unui spațiu suficient în vechea generație la obiecte de poziție - ca Această fază durează, în medie, mai mult decât faza de colectare a gunoiului completă atunci când tranzitează GC. Ca rezultat - poate crește durata de cel mai grav caz de colectare a gunoiului, este necesar să se evite revarsarile frecvente generație veche. Ca o regulă, - în timpul tranziției la ConcMarkSweep GC recomandat pentru a mări dimensiunea de generare vechi 20-30% - termen JVM cu următorii parametri: java -Xms1680m -Xmx1680m -Xmn400m -XX: + UseConcMarkSweepGC -XX: PermSize = 20m ru.skuptsov.MemoryConsumer
Pauza generală a fost redusă la 1.923 s.
Ajustarea dimensiunii de succesori sub graficul de mai jos puteți vedea cantitatea de memorie distribuirea aplicațiilor în funcție de numărul de tranziții între etapele de Eden, Survivor1 și Survivor2 înainte de a ajunge la generația veche. Adevărul este că o modalitate de a reduce numărul de overflow din vechea generație ConcMarkSweep GC - împiedică fluxul direct al obiectelor din generația tânără direct în vechiul - ocolind supraviețuitor oblasti.Dlya de urmărire distribuirea obiectelor pe scenă, puteți începe JVM cu opțiunea -XX: + PrintTenuringDistribution. În gc.log putem observa:
Dimensiunea dorita supraviețuitor 20971520 bytes nou prag 1 (maxim 4) - Vârsta 1: 40900584 bytes, 40,900,584 totală dimensiunea totală obiecte supraviețuitor - 40900584, CMS foloseste implicit de 50% de ocupare regiune barieră supraviețuitor. Astfel obținem dimensiunea domeniului
80 MB. Când executați, este setat parametrul JVM -XX: SurvivorRatio, care este determinată de formula: supraviețuitoare mărimea spațiului = -Xmn / (- XX: SurvivorRatio = + 2) pentru a obține
java -Xms1680m -Xmx1680m -Xmn400m -XX: SurvivorRatio = 3 -XX: + UseConcMarkSweepGC -XX: PermSize = 20m ru.skuptsov.MemoryConsumer Vrând să părăsească spațiu eden dimensiunea aceeași - obținem: java -Xms1760m -Xmx1760m -Xmn480m -XX: SurvivorRatio = 5 -XX: + UseConcMarkSweepGC -XX: PermSize = 20m ru.skuptsov.MemoryConsumer
Distribuția este mai bine, dar timpul total nu de mult sa schimbat din cauza specificul aplicației, faptul este că, după frecvente colecții de gunoi mici dimensiunea obiectelor supraviețuitoare este întotdeauna mai mare decât dimensiunea disponibile zonelor supraviețuitoare, astfel încât în acest caz, putem dona distribuția corectă în favoarea dimensiunii eden spațiu:
java -Xms1760m -Xmx1760m -Xmn480m -XX: SurvivorRatio = 100 -XX: + UseConcMarkSweepGC -XX: PermSize = 20m ru.skuptsov.MemoryConsumer
Rezultat Ca rezultat, am fost capabili de a reduce dimensiunea totală a pauzei cu un 3227 la 1481 cu 30 pentru a experimenta un pic în timp ce creșterea consumului global de memorie. Un lot sau un pic - depinde de caracteristicile specifice, în special, având în vedere tendința de a reduce costul de memorie fizică și principiul maximizării utilizarea memoriei - este important să se găsească un echilibru între diferitele zone ale GC și procesul este mai creativ decât științific.