Sprievodca po System.gc ()

1. Prehľad

V tomto výučbe sa chystáme preskúmať System.gc () metóda umiestnená v java.lang balíček.

Výslovne volanie System.gc () je známe, že je zlým postupom. Pokúsme sa pochopiť, prečo a či existujú nejaké prípady použitia, keď by volanie tejto metódy mohlo byť užitočné.

2. Zber odpadu

Virtuálny počítač Java sa rozhodne vykonať odvoz odpadu, ak existujú náznaky, že to má urobiť. Tieto indikácie sa líšia od jednej implementácie GC k druhej. Vychádzajú z rozdielnej heuristiky. Existuje však niekoľko okamihov, kedy bude GC vykonaný pre istotu:

  • Nová generácia (Tenured space) je plná, čo vyvoláva menšie GC
  • Stará generácia (priestory Eden + Survivor0 + Survivor1) je plná, čo spúšťa hlavnú / úplnú GC

Jediná vec, ktorá je nezávislá od implementácie GC, je oprávnenosť objektu na zhromažďovanie odpadkov.

Teraz sa pozrieme na System.gc () samotná metóda.

3. System.gc ()

Vyvolanie metódy je jednoduché:

System.gc ()

Oficiálna dokumentácia Oracle uvádza, že:

Volá sa gc metóda navrhuje že Java Virtual Machine vynakladá úsilie na recykláciu nepoužívaných objektov s cieľom sprístupniť pamäť, ktorú v súčasnosti zaberajú, na rýchle opätovné použitie.

Neexistuje žiadna záruka, že dôjde k spusteniu skutočného GC.

System.gc () spúšťa veľkú GC. Z tohto dôvodu existuje riziko, že budete musieť stráviť nejaký čas fázou stop-the-world, v závislosti od implementácie zberača odpadu. Ako výsledok, máme nespoľahlivý nástroj s potenciálne významným trestom za výkon.

Existencia explicitného vyvolania zberu odpadu by mala byť vážnou varovnou značkou pre všetkých.

Môžeme zabrániť System.gc () od vykonávania akejkoľvek práce pomocou -XX: DisableExplicitGC Vlajka JVM.

3.1. Ladenie výkonu

Stojí za zmienku, že tesne pred hodom OutOfMemoryError, JVM uskutoční úplnú GC. Preto výslovná výzva k System.gc () nás nezachráni pred neúspechom.

Smetiari sú v dnešnej dobe skutočne inteligentní. Majú všetky vedomosti o využití pamäte a ďalšie štatistické údaje, aby boli schopní robiť správne rozhodnutia. Preto by sme im mali dôverovať.

V prípade problémov s pamäťou máme množstvo nastavení, ktoré môžeme zmeniť, aby sme vyladili našu aplikáciu - počnúc výberom iného zberača odpadkov, cez nastavenie požadovaného časového pomeru času aplikácie / času GC a nakoniec až po nastavenie pevných veľkostí pamäťových segmentov.

Existujú aj spôsoby, ako zmierniť účinky Full GC spôsobené explicitným volaním. Môžeme použiť jednu z vlajok:

-XX: + ExplicitGCInvokesConcurrent

alebo:

-XX: + ExplicitGCInvokesConcurrentAndUnloadsClasses

Ak skutočne chceme, aby naša aplikácia fungovala správne, mali by sme vyriešiť skutočný problém s pamäťou.

V nasledujúcej kapitole uvidíme praktický príklad pri výslovnom volaní System.gc () sa zdá byť užitočná.

4. Príklad použitia

4.1. Scenár

Poďme napísať testovaciu aplikáciu. Chceme nájsť situáciu, keď voláme System.gc () môže byť užitočné.

Menší zber odpadu sa deje častejšie ako pri väčšom. Mali by sme sa teda pravdepodobne zamerať na to druhé. Jeden objekt sa presunie do udržovaného priestoru, ak „prežil“ niekoľko zbierok a je stále dosiahnuteľný z koreňov GC.

Poďme si predstaviť, že máme obrovskú zbierku predmetov, ktoré sú istý čas nažive. Potom v určitom okamihu vyčistíme zbierku objektov. Možno je to vhodný okamih na beh System.gc ()?

4.2. Demo aplikácia

Vytvoríme jednoduchú konzolovú aplikáciu, ktorá nám umožní simulovať tento scenár:

public class DemoApplication {private static final Map cache = new HashMap (); public static void main (String [] args) {Scanner scanner = new Scanner (System.in); while (scanner.hasNext ()) {final String next = scanner.next (); if ("fill" .equals (next)) {for (int i = 0; i <1000000; i ++) {cache.put (randomUUID (). toString (), randomUUID (). toString ()); }} else if ("invalidate" .equals (next)) {cache.clear (); } else if ("gc" .equals (next)) {System.gc (); } else if ("exit" .equals (next)) {System.exit (0); } else {System.out.println ("neznámy"); }}}}

4.3. Spustenie ukážky

Spustime našu aplikáciu s niekoľkými ďalšími príznakmi:

-XX: + PrintGCDetails -Xloggc: gclog.log -Xms100M -Xmx500M -XX: + UseConcMarkSweepGC

Prvé dva príznaky sú potrebné na zaznamenanie informácií GC. Nasledujúce dva príznaky nastavujú počiatočnú veľkosť haldy a potom maximálnu veľkosť haldy. Chceme, aby veľkosť haldy bola nízka, aby bola GC prinútená byť aktívnejšou. Nakoniec sa rozhodneme použiť CMS - zberač súbežných značiek a Sweep. Je čas spustiť našu aplikáciu!

Najprv poďme skúste vyplniť obývaný priestor. Typ vyplniť.

Môžeme to vyšetriť gclog.log súbor, aby ste zistili, čo sa stalo. Uvidíme okolo 15 zbierok. Riadok prihlásený pre jednotlivé zbierky vyzerá takto:

197,057: [GC (zlyhanie pridelenia) 197,057: [ParNew: 67498K-> 40K (75840K), 0,0016945 s] 168754K-> 101295K (244192K), 0,0017865 s]] [Časy: používateľ = 0,01 sys = 0,00, reálne = 0,00 s] s]

Ako vidíme, pamäť je zaplnená.

Ďalej, poďme sila System.gc () zadaním gc. Vidíme, že využitie pamäte sa výrazne nezmenilo:

238,810: [Full GC (System.gc ()) 238,810: [CMS: 101255K-> 101231K (168352K); 0,2634318 s] 120693K -> 101231K (244192K), [Metaspace: 32186K-> 32186K (1079296K)], 0,2635908 s] [Časy: používateľ = 0,27 sys = 0,00, reálne = 0,26 s]

Po niekoľkých ďalších behoch uvidíme, že veľkosť pamäte zostane na rovnakej úrovni.

Poďme vyčistiť vyrovnávaciu pamäť zadaním zneplatniť. Mali by sme vidieť, že sa v riadku gclog.log spis.

Môžeme sa pokúsiť vyplniť medzipamäť ešte niekoľkokrát, ale žiadny GC sa nedeje. Toto je okamih, keď môžeme prekabátiť smetiara. Teraz, po vynútení GC, uvidíme riadok ako:

262,124: [Full GC (System.gc ()) 262,124: [CMS: 101523K-> 14122K (169324K); 0,0975656 s] 103369K -> 14122K (245612K), [Metaspace: 32203K-> 32203K (1079296K)], 0,0977279 s] [Časy: používateľ = 0,10 sys = 0,00, reálne = 0,10 s]

Vydali sme pôsobivé množstvo pamäte! Ale bolo to práve teraz skutočne potrebné? Čo sa stalo?

Podľa tohto príkladu volanie System.gc () sa môže zdať lákavé, keď uvoľňujeme veľké objekty alebo zneplatňujeme kešky.

5. Iné použitie

Existuje len veľmi málo dôvodov, prečo je výslovná výzva k System.gc () metóda môže byť užitočná.

Jedným z možných dôvodov je čistenie pamäte po štarte servera - spúšťame server alebo aplikáciu, ktorá sa veľmi pripravuje. Potom je potrebné finalizovať množstvo objektov. Za čistenie po takejto príprave by však nemala byť naša zodpovednosť.

Ďalším je analýza úniku pamäteje to viac ladiaca prax ako niečo, čo by sme chceli ponechať v produkčnom kóde. Telefonovanie System.gc () a videnie stále veľkého množstva haldy môže byť znakom úniku pamäte.

6. Zhrnutie

V tomto článku sme skúmali System.gc () metóda a kedy by sa to mohlo zdať užitočné.

Nikdy by sme sa nemali spoliehať na to, pokiaľ ide o správnosť našej aplikácie. GC je vo väčšine prípadov inteligentnejší ako my a v prípade akýchkoľvek problémov s pamäťou by sme mali namiesto pôvodného explicitného volania zvážiť vyladenie virtuálneho stroja.

Ako obvykle, kód použitý v tomto článku nájdete na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found