Veiledning til System.gc ()

1. Oversikt

I denne opplæringen skal vi undersøke System.gc () metoden ligger i java.lang pakke.

Eksplisitt ringer System.gc () er kjent for å være en dårlig praksis. La oss prøve å forstå hvorfor og om det er noen brukstilfeller når vi kaller denne metoden kan være nyttig.

2. Søppelinnsamling

Java Virtual Machine bestemmer seg for å utføre søppeloppsamling når det er indikasjoner på det. Disse indikasjonene er forskjellige fra en GC-implementering til en annen. De er basert på forskjellige heuristikker. Imidlertid er det noen øyeblikk når GC vil bli utført sikkert:

  • Ny generasjon (Tenured space) er full, noe som utløser mindre GC
  • Gammel generasjon (Eden + Survivor0 + Survivor1 mellomrom) er full, noe som utløser større / full GC

Det eneste som er uavhengig av GC-implementeringen er gjenstand for gjenstand for søppel.

Nå skal vi se på System.gc () selve metoden.

3. System.gc ()

En påkalling av metoden er enkel:

System.gc ()

Den offisielle Oracle-dokumentasjonen sier at:

Ringer til gc metode foreslår at Java Virtual Machine bruker krefter på å resirkulere ubrukte objekter for å gjøre minnet de for øyeblikket opptar tilgjengelig for rask gjenbruk.

Det er ingen garanti for at den faktiske GC vil bli utløst.

System.gc () utløser en større GC. Derfor er det en risiko for å bruke litt tid på stop-the-world-fasen, avhengig av søppeloppsamleren. Som et resultat, vi har et upålitelig verktøy med potensielt betydelig ytelsesstraff.

Eksistensen av eksplisitt søppelinnsamling bør være et seriøst rødt flagg for alle.

Vi kan forhindre System.gc () fra å gjøre noe arbeid ved å bruke -XX: DisableExplicitGC JVM-flagg.

3.1. Performance Tuning

Det er verdt å merke seg at rett før du kaster en OutOfMemoryError, JVM vil utføre en full GC. Derfor en eksplisitt oppfordring til System.gc () vil ikke redde oss fra feil.

Søppeloppsamlere i dag er veldig smarte. De har all kunnskap om minnebruk og annen statistikk for å kunne ta riktige beslutninger. Derfor bør vi stole på dem.

I tilfelle minneproblemer har vi en rekke innstillinger vi kan endre for å stille inn applikasjonen vår - fra å velge en annen søppeloppsamler, gjennom å angi ønsket applikasjonstid / GC-tidsforhold, og til slutt, med å sette faste størrelser for minnesegmenter.

Det er også måter å redusere effekten av Full GC forårsaket av en eksplisitt samtale. Vi kan bruke et av flaggene:

-XX: + EksplisittGCInvokesConcurrent

eller:

-XX: + EksplisittGCInvokesConcurrentAndUnloadsClasses

Hvis vi virkelig vil at appen vår skal fungere skikkelig, bør vi løse det virkelige underliggende minneproblemet.

I neste kapittel vil vi se et praktisk eksempel når vi eksplisitt ringer System.gc () ser ut til å være nyttig.

4. Brukseksempel

4.1. Scenario

La oss skrive en testapp. Vi ønsker å finne en situasjon når vi ringer System.gc () kan være nyttig.

Mindre søppeloppsamling skjer oftere enn den store. Så vi bør nok fokusere på sistnevnte. Et enkelt objekt flyttes til et fast område hvis det “overlevde” noen få samlinger og fremdeles kan nås fra GC-røtter.

La oss forestille oss at vi har en enorm samling av gjenstander som lever i noen tid. På et tidspunkt tømmer vi samlingen av objekter. Kanskje det er et godt øyeblikk å løpe System.gc ()?

4.2. Demo-applikasjon

Vi oppretter en enkel konsollapp som lar oss simulere dette scenariet:

offentlig klasse DemoApplication {privat statisk slutt Kartbuffer = ny HashMap (); public static void main (String [] args) {Scanner scanner = new Scanner (System.in); mens (scanner.hasNext ()) {final String next = scanner.next (); hvis ("fyll". er lik (neste)) {for (int i = 0; i <1000000; i ++) {cache.put (randomUUID (). toString (), randomUUID (). toString ()); }} annet hvis ("ugyldiggjøre" .equals (neste)) {cache.clear (); } annet hvis ("gc" .equals (neste)) {System.gc (); } annet hvis ("exit" .equals (neste)) {System.exit (0); } annet {System.out.println ("ukjent"); }}}}

4.3. Kjører demonstrasjonen

La oss kjøre applikasjonen vår med noen få ekstra flagg:

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

De to første flaggene er nødvendige for å logge GC-informasjon. De to neste flaggene setter innledende haugestørrelse og deretter maksimal haugestørrelse. Vi vil holde dyngestørrelsen lav for å tvinge GC til å være mer aktiv. Til slutt bestemmer vi oss for å bruke CMS - Concurrent Mark and Sweep søppeloppsamler. Det er på tide å kjøre appen vår!

Først, la oss prøv å fylle fast plass. Type fylle.

Vi kan undersøke vår gclog.log fil for å se hva som skjedde. Vi får se rundt 15 samlinger. Linjen som er logget for enkeltsamlinger ser ut som:

197.057: [GC (Allocation Failure) 197.057: [ParNew: 67498K-> 40K (75840K), 0.0016945 sec] 168754K-> 101295K (244192K), 0.0017865 secs] [Times: user = 0.01 sys = 0.00, real = 0.00 secs] sekunder]

Som vi kan se, er minnet fylt.

Neste, la oss makt System.gc () ved å skrive gc. Vi kan se at minnebruk ikke endret seg vesentlig:

238.810: [Full GC (System.gc ()) 238.810: [CMS: 101255K-> 101231K (168352K); 0.2634318 sek] 120693K-> 101231K (244192K), [Metaspace: 32186K-> 32186K (1079296K)], 0.2635908 sek] [Times: user = 0.27 sys = 0.00, real = 0.26 sec]

Etter noen flere kjøringer ser vi at minnestørrelsen holder seg på samme nivå.

La oss tøm hurtigbufferen ved å skrive ugyldiggjøre. Vi skal ikke se flere logglinjer vises i gclog.log fil.

Vi kan prøve å fylle hurtigbufferen noen ganger til, men ingen GC skjer. Dette er et øyeblikk når vi kan overliste søppeloppsamleren. Nå, etter å ha tvunget GC, ser vi en linje som:

262.124: [Full GC (System.gc ()) 262.124: [CMS: 101523K-> 14122K (169324K); 0,0975656 sek] 103369K-> 14122K (245612K), [Metaspace: 32203K-> 32203K (1079296K)], 0,0977279 sek] [Times: bruker = 0,10 sys = 0,00, real = 0,10 sek]

Vi har gitt ut imponerende mye minne! Men var det virkelig nødvendig akkurat nå? Hva skjedde?

I følge dette eksemplet, ringer System.gc () kan virke fristende når vi slipper store gjenstander eller ugyldiggjør cacher.

5. Andre bruksområder

Det er veldig få grunner når en eksplisitt samtale til System.gc () metoden kan være nyttig.

En mulig årsak er rengjøring av minne etter serverstart - vi starter en server eller applikasjon som gjør mye forberedelser. Etter det er det mange gjenstander som skal fullføres. Rengjøring etter slik klargjøring bør imidlertid ikke være vårt ansvar.

En annen er analyse av minnelekkasjerdet er mer en feilsøkingspraksis enn noe vi ønsker å ha i produksjonskoden. Ringer System.gc () og å se haugeplassen fortsatt er høy kan være en indikasjon på minnelekkasje.

6. Sammendrag

I denne artikkelen undersøkte vi System.gc () metode og når det kan virke nyttig.

Vi bør aldri stole på det når det gjelder riktigheten av appen vår. GC er i de fleste tilfeller smartere enn oss, og i tilfelle minneproblemer, bør vi vurdere å stille inn den virtuelle maskinen i stedet for å ringe så eksplisitt.

Som vanlig kan koden som brukes i denne artikkelen finnes på GitHub.


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