1. Jätteen kierrätysmekanismin merkitys Merkittävä ominaisuus Java-kielessä on roskien keräysmekanismin käyttöönotto, joka ratkaisee C++-ohjelmoijille hankalimman muistinhallintaongelman, joten Java-ohjelmoijien ei enää tarvitse ottaa muistinhallintaa huomioon ohjelmia kirjoittaessaan. Roskien keräysmekanismin vuoksi Java-olioilla ei enää ole käsitettä "scope", vaan vain objektin viitteellä on "scope".Jätehuolto voi tehokkaasti estää muistivuodon ja käyttää tehokkaasti tyhjäkäyntimuistia.
ps:内存泄露是指该内存空间使用完毕之后未回收,在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度,我们有时也将其称为“对象游离”。
2. Algoritmit jätehuoltomekanismeissa Java-kielen määrittely ei määrittele erikseen, mitä roskien keräysalgoritmia JVM:ssä käytetään, mutta minkä tahansa roskien keräysalgoritmin on yleensä tehtävä kaksi perusasiaa: (1) löytää hyödyttömiä informaatioobjekteja; (2) Palauttaa hyödyttömien objektien täyttämä muistitila, jotta ohjelma voi käyttää tilaa uudelleen.
1. Viitelaskennan kerääjä 1.1 Algoritmianalyysi
Viitelaskenna on varhainen strategia jätekerääjissä. Tässä lähestymistavassa jokaiselle heapin objekti-instanssille on viitemäärä. Kun objekti luodaan ja objektiinstanssi liitetään muuttujalle, muuttujien määrä asetetaan arvoon 1. Kun mikä tahansa muu muuttuja annetaan viitteeksi tälle oliolle, lukumäärä lisätään yhdellä (a = b, jolloin b:llä viitatun objekti-instanssin laskuri on +1), mutta kun viittaus olioinstanssiin on ylittänyt elinikänsä tai se asetetaan uudelle arvolle, objekti-instanssin viitelaskuri vähennetään yhdellä arvolla. Mikä tahansa esineen instanssi, jonka viitelaskuri on 0, voidaan kerätä roskaksi. Kun objekti-instanssi kerätään roskia, minkä tahansa viittaavan objektin viitelaskuri on miinus 1. 1.2 Edut ja haitat Ansio:
Referenssilukujen kerääjä voidaan suorittaa hyvin nopeasti, integroituna ohjelman suoritukseen. Se on hyödyllinen reaaliaikaisissa ympäristöissä, joissa ohjelmia ei tarvitse keskeyttää pitkiä aikoja. Puute:
Pyöreitä viittauksia ei voida havaita. *Jos vanhemmalla oliolla on viittaus lapsiobjektiin, lapsiobjekti puolestaan viittaa vanhempiobjektiin. Näin heidän viittausmääränsä ei voi koskaan olla 0. 1.3 Viitelaskennan algoritmi ei pysty ratkaisemaan ympyränmuotoista viiteongelmaa, esimerkiksi:
/** * Java学习交流QQ群:589809992 我们一起学Java! */public class Main { public static void main(String[] args) { MyObject object1 = new MyObject(); MyObject object2 = new MyObject(); object1.object = object2; object2.object = object1; object1 = null; object2 = null; }} Viimeiset kaksi lausetta määrittelevät object1:n ja object2:n nollaksi, mikä tarkoittaa, että object1:n ja object2:n osoittamiin objekteihin ei enää pääse käsiksi, mutta koska ne viittaavat toisiinsa, niiden viitelaskurit eivät ole 0, joten roskienkerääjä ei koskaan kierrätä niitä.
2. Jäljityskeräin eli merkitse ja pyyhkäisy -algoritmi 2.1 Juurihakualgoritmi
Juurihakualgoritmi on otettu käyttöön diskreetin matematiikan graafiteoriasta, ohjelma käsittelee kaikki viitesuhteet graafina, alkaen solmusta GC ROOT, etsien vastaavaa viitesolmua, ja löydettyään tämän solmun, jatkaen tämän viitesolmun etsimistä, kun kaikki viitesolmut on haettu, jäljelle jääneet solmut katsotaan viittaamattomiksi solmuiksi, eli hyödyttömiksi solmuiksi. Java, jota voi käyttää GC-juurena 1. Virtuaalikonepinossa viitatut objektit (paikalliset muuttujataulukko) 2. Objekti, johon viitataan metodialueen staattisen attribuutin kautta 3. Objekti, johon vakio viittaa metodialueella 4. Viitatut objektit paikallisessa metodipinossa (natiiviobjektit)
2.2 Jäljitysalgoritmin kaaviokaavio
![]()
2.3 Merkkien puhdistusalgoritmin analyysi
Tagien puhdistusalgoritmi skannaa juurikokoelmasta, merkitsee jäljelle jääneet objektit ja skannaa sitten koko tilan tägäimättömien objektien varalta kierrätettäväksi, kuten yllä olevassa kuvassa näkyy. Tag-puhdistusalgoritmin ei tarvitse siirtää objekteja, vaan se käsittelee vain ei-säilyviä objekteja, mikä on erittäin tehokasta, kun jäljellä olevia objekteja on paljon, mutta koska tag-puhdistusalgoritmi kierrättää suoraan ei-selviytyviä objekteja, se aiheuttaa muistin pirstoutumista.
3. Pakkausalgoritmi tai etikettien viimeistelyalgoritmi
![]()
Tag-finish-algoritmi käyttää samaa menetelmää kuin tag-clear-algoritmi olioiden merkitsemiseen, mutta se on eri tavalla puhdistuksessa: kun ei-selviytyvien objektien tila on palautettu, se siirtää kaikki jäljelle jääneet objektit vasempaan päähän ja päivittää vastaavan osoittimen. Tag-finish-algoritmi perustuu tag-puhdistusalgoritmiin ja siirtää objekteja, joten se on kalliimpi, mutta ratkaisee muistin pirstoutumisen ongelman. Compacting-algoritmiin perustuvien keräimien toteutuksessa lisätään yleensä kahvat ja kahvataulukot.
4. Kopiointialgoritmi (Compacting Collector)
![]()
Algoritmin tarkoituksena on voittaa kahvan ylikuormitus ja ratkaista kasan jätteiden kerääminen. Kun objekti on täynnä, kopioalgoritmin pohjainen roskien kerääjä skannaa aktiivisen objektin juurijoukosta ja kopioi jokaisen aktiivisen objektin vapaaseen pintaan (jotta aktiivisen objektin muistin väliin ei jää vapaita aukkoja), jolloin vapaa pinta muuttuu objektin kasvoksi, alkuperäinen objektin pinta vapaaksi ja ohjelma varaa muistin uudelle objektipinnalle. Tyypillinen selviytymisalgoritmiin perustuva roskien keruu on stop-and-copy -algoritmi, joka jakaa kasan objektikasvoihin ja vapaan alueen kasvoihin, ja ohjelma keskeyttää suorituksen vaihdettaessa objektipinkojen ja vapaiden alueiden pintojen välillä.
5. Sukupolvien keräilijä
![]()
Sukupolvien jätteiden kierrätysstrategia perustuu siihen, ettäEri esineiden elinkaari on erilainen。 Siksi eri elinkaarilla varustetut esineet voivat ottaa käyttöön erilaisia kierrätysalgoritmeja kierrätyksen tehokkuuden parantamiseksi.
Nuori sukupolvi 1. Kaikki uudet esineet sijoitetaan ensin nuoremmalle sukupolvelle. Nuoremman sukupolven tavoitteena on kerätä lyhyen elinkaaren omaavat esineet mahdollisimman nopeasti.
2. Uuden sukupolven muisti on jaettu yhteen Edenin alueeseen ja kahteen selviytyjävyöhykeeseen (selviytyjä0, selviytyjä1) suhteessa 8:1:1. Yksi Eden-alue, kaksi Selviytyjä-aluetta (yleisesti). Suurin osa esineistä ilmestyy Edenin alueelle. Kun selviytyjä0-alue on myös täynnä, eden-alue ja selviytyjä0-alue kopioidaan toiseen selviytyjä1-alueeseen, ja sitten eden- ja selviytyjä0-alue tyhjennetään, ja selviytyjä0-alue on tyhjä, ja sitten selviytyjä0-alue ja selviytyjä1-alue vaihdetaan. Eli pidä selviytyjä1-alue tyhjänä ja niin edelleen.
3. Kun selviytyjä 1 -alue ei riitä säilyttämään Edenin ja Survivor0:n säilyneitä esineitä, jäljelle jääneet esineet tallennetaan suoraan vanhaan aikakauteen. Jos vanhuus on myös täynnä, se laukaisee täyden GC:n, eli uuden sukupolven ja vanhan sukupolven kierrätyksen
4. Uuden sukupolven GC:tä kutsutaan myös Minor GC:ksi, ja MinorGC:n esiintymistiheys on suhteellisen korkea (se ei välttämättä laukeudu, kun Edenin alue on täynnä)
Vanha sukupolvi
1. Esineet, jotka ovat vielä elossa nuoremman sukupolven N roskien kierrätyksen jälkeen, sijoitetaan vanhemmalle sukupolvelle. Tästä syystä voidaan katsoa, että vanha sukupolvi on varastoitu joihinkin esineisiin, joilla on pitkä elinkaari.
2. Muisti on myös paljon suurempi kuin uuden sukupolven muisti (likimääräinen suhde on 1:2), kun vanhan ajan muisti on täynnä, Major GC aktivoituu, eli täysi GC, Full GC:n taajuus on suhteellisen alhainen, vanhan esineen selviytymisaika on suhteellisen pitkä ja selviytymisprosentti on korkea.
Pysyvä sukupolvi Käytetään staattisten tiedostojen, kuten Java-luokkien, metodien jne. tallentamiseen. Pysyvät sukupolvet eivät vaikuta merkittävästi roskien keräämiseen, mutta jotkut sovellukset voivat dynaamisesti generoida tai kutsua joitakin luokkia, kuten Hibernate jne., ja tässä tapauksessa näiden uusien luokkien tallentamista varten täytyy asettaa suhteellisen suuri pysyvä generointitila ajonajan aikana.
3. GC (jätehuolto)Uuden sukupolven keräilijöiden käyttämät keräilijät: Serial, PraNew, Parallel Scavenge Vanhusten keräilijöiden käyttämät keräilijät: Serial Old, Parallel Old, CMS
![]()
Sarjakeräin (replikaatioalgoritmi) Uuden sukupolven yksikierteiset keräimet, merkinnät ja puhdistus ovat yksikierteisiä, etuna yksinkertaisuus ja tehokkuus.
Sarjallinen vanha keräilijä (Label-Finish -algoritmi) Old Age Single Thread Collector, Old Age -versio sarjakeräilijästä.
ParNew-keräin (stop-copy -algoritmi) Uuden sukupolven keräintä voidaan pitää monisäikeisenä versiona Serial Collectorista, jolla on parempi suorituskyky kuin Serialilla moniytimisessä suoritinympäristössä.
Rinnakkainen keräinkeräin (pysäytys-kopioalgoritmi) Rinnakkaiskeräimet korkeaan läpimenoon ja tehokkaaseen suorittimen käyttöön. Läpäisykyky on yleensä 99 %, ja läpimenonopeus = käyttäjän säikeaika / (käyttäjän säieaika + GC-säieaika). Se soveltuu taustasovelluksiin, joissa ei vaadita suurta vuorovaikutusta.
Rinnakkainen vanha keräin (pysäytys-kopioalgoritmi) Vanhempi versio Parallel Scavenge -keräimästä, rinnakkaiskeräin, jossa on läpäisyprioriteetti
CMS (Concurrent Mark Sweep) Collector (Mark-Clean -algoritmi) Korkea samanaikaisuus, matala tauko, lyhimmän GC:n palautusajan tavoittelua, korkea prosessorin käyttö, nopea vasteaika, lyhyt taukoaika ja moniytiminen suoritin tavoittelee korkeaa vasteaikaa
4. GC:n toteutusmekanismiKoska esinettä on käsitelty eri sukupolvissa, myös jätteiden keräysalue ja -aika eroavat. GC:tä on kahta tyyppiä: Scavenge GC ja Full GC.
Scavenge GC Normaalisti, kun uusi objekti luodaan eikä se hae tilaa Edenissä, Scavenge GC aktivoituu, mikä GC:ää Edenin alueella, puhdistaa ei-selviytyvät esineet ja siirtää selviytyneet esineet Survivor-alueelle. Sitten lajittele Survivorin kaksi aluetta. GC tehdään tällä tavalla nuoremman sukupolven Eden-alueella eikä vaikuta vanhempaan sukupolveen. Koska suurin osa kohteista alkaa Edenin alueelta, eikä Edenin aluetta ole varattu paljon, Edenin alueen GC tehdään usein. Siksi on yleensä tarpeen käyttää nopeita ja tehokkaita algoritmeja, jotta Eden vapautuu mahdollisimman pian.
Täysi kokonaisluku Järjestä koko pino, mukaan lukien Young, Tenured ja Perm. Täysi GC on hitaampaa kuin Scavenge GC, koska se vaatii koko kasan kierrätyksen, joten täysien GC:iden määrää tulisi vähentää mahdollisimman paljon. Suuri osa JVM-viritysprosessista on FullGC:n virittämistä. Täysi GC voi johtua seuraavista syistä: 1. Vakinainen on kirjoitettu täysi 2. Permanentti on kirjoitettu täynnä. 3. System.gc() näytetään kutsuna 4. Heapin domain-allokointistrategia muuttuu dynaamisesti viimeisen GC:n jälkeen
5. Java GC:llä on myös muistivuoto-ongelmia1. Staattisten kokoelmaluokkien, kuten HashMapin, Vectorin jne. käyttö on alttiimpia muistivuodoille, ja näiden staattisten muuttujien elinkaari on sama kuin sovelluksen, eikä kaikkia objekteja voida vapauttaa, koska niitä sovelletaan aina Vectorin ja muiden toimesta. Staattinen vektori v = uusi vektori(); kun (int i = 1; i<100; i++) { Object o = uusi Objekti(); v.add(o); o = nolla; } Tässä esimerkissä koodipinossa on viite v vektoriobjektille ja viite o objektiobjektille. For-silmukassa generoimme jatkuvasti uusia objekteja, lisäämme ne vektoriobjektiin ja lopulta nollaamme o-viittauksen. Kysymys kuuluu, kun o-viittaus mitätöidään, voiko GC kierrättää luomamme objektiobjektin GC:llä? Vastaus on ei. Koska kun GC seuraa viittauksia koodipinossa, se löytää v viitteen, ja jos jatkat jäljittämistä, huomaat, että muistitilassa on viittauksia Object-objekteihin, joihin viitataan v viittaukset. Tämä tarkoittaa, että vaikka o-viite on tyhjennetty, on silti muita viittauksia Object-objektiin, joihin voi pääseä käsiksi, joten GC ei voi vapauttaa niitä. Jos tämän silmukan jälkeen Object-objektilla ei ole vaikutusta ohjelmaan, oletetaan, että Java-ohjelmassa on muistivuoto. 2. Erilaiset yhteydet, tietokantayhteydet, verkkoyhteydet, IO-yhteydet jne. eivät näytä puhelua lähellä, eikä GC kierrätä niitä, mikä johtaa muistivuotoon. 3. Kuuntelijoiden käyttö voi myös aiheuttaa muistivuotoa, kun kuuntelijaa ei poisteta objektin vapauttamisen aikana.
|