Útmutató a System.gc ()

1. Áttekintés

Ebben az oktatóanyagban megvizsgáljuk a System.gc () módszer található a java.lang csomag.

Kifejezetten hív System.gc () rossz gyakorlatról ismert. Próbáljuk megérteni, hogy miért, és vannak-e olyan esetek, amikor ez a módszer hasznos lehet.

2. Szemétgyűjtés

A Java virtuális gép úgy dönt, hogy szemetet gyűjt, ha erre utaló jelek vannak. Ezek a jelek GC-megvalósításonként eltérnek. Különböző heurisztikákon alapulnak. Van azonban néhány pillanat, amikor a GC biztosan végrehajtásra kerül:

  • Az új generáció (Tenured space) megtelt, ami kisebb GC-t vált ki
  • A régi generáció (Eden + Survivor0 + Survivor1 szóköz) megtelt, ami beindítja a nagyobb / teljes GC-t

Az egyetlen dolog, amely független a GC megvalósításától, az a tárgyi jogosultság a szemétszállításra.

Most megnézzük a System.gc () maga a módszer.

3. System.gc ()

A módszer meghívása egyszerű:

System.gc ()

Az Oracle hivatalos dokumentációja szerint:

Felhívás a gc módszer javasolja hogy a Java virtuális gép erőfeszítéseket fordít a fel nem használt objektumok újrahasznosítására annak érdekében, hogy az általuk jelenleg elfoglalt memória gyors újrafelhasználás céljából rendelkezésre álljon.

Nincs garancia arra, hogy a tényleges GC bekapcsol.

System.gc () nagy GC-t vált ki. Ezért fennáll annak a kockázata, hogy egy kis időt töltsön a világ megálló szakaszában, a hulladékgyűjtő megvalósításától függően. Ennek eredményeként megbízhatatlan eszközünk van, potenciálisan jelentős teljesítménybüntetéssel.

A kifejezett szemétszállításra való felhívásnak mindenki számára komoly vörös zászlónak kell lennie.

Megelőzhetjük System.gc () hogy bármilyen munkát végezzen a -XX: DisableExplicitGC JVM zászló.

3.1. Teljesítmény növelés

Érdemes megjegyezni, hogy közvetlenül az an dobása előtt OutOfMemoryError, a JVM teljes GC-t fog teljesíteni. Ezért kifejezett felhívás a System.gc () nem fog megmenteni a kudarctól.

A szemétgyűjtők manapság nagyon okosak. Minden tudással rendelkeznek a memória használatáról és egyéb statisztikákról, hogy megfelelő döntéseket tudjanak hozni. Ezért bíznunk kell bennük.

Memóriaproblémák esetén egy csomó olyan beállítással rendelkezünk, amelyeket megváltoztathatunk az alkalmazásunk hangolásához - kezdve egy másik szemétgyűjtő kiválasztásától a kívánt alkalmazási idő / GC időarány beállításáig, végül a memóriaszegmensek rögzített méreteinek beállításával.

A kifejezett GC által okozott Full GC hatásainak mérséklésére is van mód. Használhatjuk az egyik zászlót:

-XX: + ExplicitGCInvokesConcurrent

vagy:

-XX: + ExplicitGCInvokesConcurrentAndUnloadsClasses

Ha valóban azt akarjuk, hogy alkalmazásunk megfelelően működjön, meg kell oldanunk a valódi mögöttes memóriaproblémát.

A következő fejezetben gyakorlati példát fogunk látni, amikor kifejezetten hívunk System.gc () hasznosnak tűnik.

4. Felhasználási példa

4.1. Forgatókönyv

Írjunk egy tesztalkalmazást. Híváskor szeretnénk helyzetet találni System.gc () hasznos lehet.

A kisebb szemétgyűjtés gyakrabban történik, mint a nagyobb. Tehát valószínűleg az utóbbira kell összpontosítanunk. Egyetlen objektum átkerül a bérelt helyre, ha néhány gyűjteményt „túlélt”, és a GC gyökereiből továbbra is elérhető.

Képzeljük el, hogy hatalmas tárgyak gyűjteménye van, amelyek egy ideje életben vannak. Aztán egy bizonyos ponton megtisztítjuk az objektumok gyűjteményét. Talán jó pillanat a futásra System.gc ()?

4.2. Demo alkalmazás

Létrehozunk egy egyszerű konzolalkalmazást, amely lehetővé teszi számunkra a forgatókönyv szimulálását:

public class DemoApplication {private static final Map cache = new HashMap (); public static void main (String [] args) {Szkenner szkenner = új Szkenner (System.in); while (scanner.hasNext ()) {final String next = szkenner.next (); if ("kitöltés" .egyenlő (következő)) {for (int i = 0; i <1000000; i ++) {cache.put (randomUUID (). toString (), randomUUID (). toString ()); }} else if ("érvénytelenít" .egyenlő (következő)) {cache.clear (); } else if ("gc" .egyenlő (következő)) {System.gc (); } else if ("exit" .egyenlő (következő)) {System.exit (0); } else {System.out.println ("ismeretlen"); }}}}

4.3. A bemutató futtatása

Futtassuk az alkalmazásunkat néhány további zászlóval:

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

Az első két jelzőre szükség van a GC információk naplózásához. A következő két zászló a kezdeti kupacméretet, majd a maximális kupacméretet állítja be. Alacsony szinten akarjuk tartani a kupac méretét, hogy a GC-t aktívabbá tegyük. Végül a CMS - Concurrent Mark and Sweep szemétszedő használatáról döntöttünk. Itt az ideje, hogy futtassuk az alkalmazást!

Először nézzük próbálja kitölteni a bérelt helyet. típus tölt.

Kivizsgálhatjuk gclog.log fájl, hogy lássa, mi történt. Körülbelül 15 gyűjteményt fogunk látni. Az egyes gyűjtemények naplózása a következőképpen néz ki:

197.057: [GC (Allocation Failure) 197.057: [ParNew: 67498K-> 40K (75840K), 0.0016945 sec] 168754K-> 101295K (244192K), 0.0017865 sec] [Idők: felhasználó = 0,01 sys = 0,00, valós = 0,00 mp] másodperc]

Mint láthatjuk, az emlék megtelt.

Ezután menjünk Kényszerítés System.gc () gépeléssel gc. Láthatjuk, hogy a memóriahasználat nem változott jelentősen:

238,810: [Teljes GC (System.gc ()) 238,810: [CMS: 101255K-> 101231K (168352K); 0,2634318 mp] 120693K-> 101231K (244192K), [Metaspace: 32186K-> 32186K (1079296K)], 0,2635908 mp] [Times: felhasználó = 0,27 sys = 0,00, valós = 0,26 mp]

Néhány további futás után látni fogjuk, hogy a memória mérete ugyanazon a szinten marad.

Nézzük törölje a gyorsítótárat gépeléssel érvénytelenít. Nem kellene látnunk több naplóvonalat a gclog.log fájl.

Megpróbálhatjuk még néhányszor feltölteni a gyorsítótárat, de nem történik GC. Ez egy olyan pillanat, amikor felülmúlhatjuk a szemétszedőt. A GC kényszerítése után egy sort fogunk látni:

262.124: [Teljes GC (System.gc ()) 262.124: [CMS: 101523K-> 14122K (169324K); 0,0975656 mp] 103369K-> 14122K (245612K), [Metaspace: 32203K-> 32203K (1079296K)], 0,0977279 mp] [Idők: felhasználó = 0,10 sys = 0,00, valós = 0,10 mp]

Lenyűgöző mennyiségű memóriát bocsátottunk ki! De vajon most valóban szükség volt-e rá? Mi történt?

E példa szerint hívás System.gc () csábítónak tűnhet, amikor nagy objektumokat bocsátunk ki vagy érvénytelenítjük a gyorsítótárakat.

5. Egyéb felhasználások

Nagyon kevés oka van annak, amikor kifejezett felhívás a System.gc () módszer hasznos lehet.

Az egyik lehetséges ok az a memória tisztítása a szerver indítása után - Elindítunk egy szervert vagy alkalmazást, amely sok előkészítést végez. Ezt követően nagyon sok objektum véglegesítésre vár. Az ilyen előkészítés utáni tisztítás azonban nem lehet a mi felelősségünk.

Egy másik az memóriaszivárgás elemzéseez inkább hibakeresési gyakorlat, mint valami, amit szeretnénk megtartani a gyártási kódban. Hívás System.gc () és ha még mindig magas a kupacterület, az memóriaszivárgásra utalhat.

6. Összefoglalás

Ebben a cikkben megvizsgáltuk a System.gc () módszer és mikor tűnhet hasznosnak.

Soha nem szabad erre támaszkodnunk, amikor az alkalmazás helyességéről van szó. A GC a legtöbb esetben okosabb, mint mi, és bármilyen memóriaprobléma esetén fontolóra kell venni a virtuális gép hangolását egy ilyen kifejezett hívás helyett.

Szokás szerint az ebben a cikkben használt kód megtalálható a GitHubon.