1. Prügi taaskasutusmehhanismi tähtsus Java keele märkimisväärne omadus on prügikogumise mehhanismi kasutuselevõtt, mis lahendab C++ programmeerijate jaoks kõige keerulisema mäluhalduse probleemi, nii et Java programmeerijad ei pea enam programmi kirjutamisel mäluhaldust arvestama. Prügikogumise mehhanismi tõttu ei ole Java objektidel enam mõistet "scope", vaid ainult objekti viitel on "scope".Prügikogumine aitab tõhusalt vältida mälulekkeid ja kasutada tühikäigu mälu.
ps:内存泄露是指该内存空间使用完毕之后未回收,在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度,我们有时也将其称为“对象游离”。
2. Algoritmid prügikogumise mehhanismides Java keele spetsifikatsioon ei täpsusta selgelt, millist prügikogumise algoritmi JVM-is kasutada, kuid iga prügikogumise algoritm peab tavaliselt tegema kahte põhilist asja: (1) leidma kasutuid infoobjekte; (2) Taastada kasutusele kasutusele võetud mäluruum, mida hõivavad kasutud objektid, et programm saaks seda ruumi uuesti kasutada.
1. Viidete loendamise koguja 1.1 Algoritmide analüüs
Viidete lugemine on varajane strateegia prügikoristajate seas. Selles lähenemises on iga objekti instantsi kohta viitearv kuhjas. Kui objekt luuakse ja objekti eksemplarile määratakse muutuja, määratakse muutujate arv väärtuseks 1. Kui sellele objektile määratakse viiteks mõni teine muutuja, liidetakse arv 1-ga (a = b, siis b viidatud objekti eksemplari loendur on +1), kuid kui objekti eksemplari viide on ületanud oma eluea või seatakse uus väärtus, lahutatakse objekti eksemplari viiteloendur väärtusega 1. Iga objekti eksemplar, mille viiteloendur on 0, võib koguda prügina. Kui objekti eksemplar kogutakse prügi, on iga viidatud objekti viiteloendur miinus 1. 1.2 Eelised ja puudused Merit:
Viitearvu kogujat saab väga kiiresti käivitada, põimituna programmi jooksuga. See on kasulik reaalajas keskkondades, kus programme ei pea pikaks ajaks katkestama. Puudus:
Ringviiteid ei ole võimalik tuvastada. *Kui vanemobjektil on viide alamobjektile, viitab lapsobjekt omakorda vanemobjektile. Nii ei saa nende viitete arv kunagi olla 0. 1.3 Viidete lugemise algoritm ei suuda lahendada ringviiteprobleemi, näiteks:
/** * 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; }} Viimased kaks lauset määravad object1 ja object2 nulliks, mis tähendab, et objekt1 ja object2 poolt osutatud objektid ei ole enam ligipääsetavad, kuid kuna need viitavad üksteisele, ei ole nende viiteloendurid 0, seega prügikoguja neid kunagi ei taaskasuta.
2. Jälgimiskoguja ehk märgi ja pühkimise algoritm 2.1 Juureotsingu algoritm
Juurotsingu algoritm on sisse toodud graafiteooriast diskreetses matemaatikas, programm käsitleb kõiki viitesuhteid graafina, alustades sõlmest GC ROOT, otsides vastavat viitesõlme, pärast selle sõlme leidmist ja jätkates selle viitesõlme otsimist, kui kõik viitesõlmed on otsitud, loetakse ülejäänud sõlmed viitamata sõlmedeks ehk kasututeks sõlmedeks. Java, mida saab kasutada GC juurena 1. Virtuaalmasina virnas viidatud objektid (kohalike muutujate tabel) 2. Objekt, millele viitab staatiline atribuut meetodi alal 3. Objekt, millele viitab konstant meetodi alal 4. Viidatud objektid lokaalses meetodipinus (natiivsed objektid)
2.2 Jälgimisalgoritmi skeemiline diagramm
![]()
2.3 Markerite puhastamise algoritmi analüüs
Siltide puhastusalgoritm skaneerib juurkogumist, märgib allesjäänud objektid ja seejärel skaneerib kogu ruumi, et leida märgistamata objekte, mida taaskasutada, nagu ülaltoodud joonisel näidatud. Sildipuhastuse algoritm ei pea objekte liigutama ja töötleb ainult mittesäilinud objekte, mis on äärmiselt tõhus, kui säilinud objekte on palju, kuid kuna sildipuhastusalgoritm taaskasutab otseselt mittesäilivaid objekte, põhjustab see mälukillustumist.
3. Kompaktimisalgoritm ehk sildi lõpetamise algoritm
![]()
Sildi lõpetamise algoritm kasutab sama meetodit nagu siltide puhastamise algoritm objektide märgistamiseks, kuid puhastamisel on see erinev – pärast mittesäilinud objektide ruumi tagasivõtmist liigub kõik ellujäänud objektid vasakpoolsesse vaba ruumi ja uuendab vastavat osutit. Sildi lõpetamise algoritm põhineb siltide puhastamise algoritmil ja liigutab objekte, mistõttu on see kallim, kuid lahendab mälu killustumise probleemi. Kompaktimise algoritmil põhinevate kollektorite rakendamisel lisatakse tavaliselt käepidemete ja käepidemete tabelid.
4. Kopeerimisalgoritm (kompaktimiskoguja)
![]()
Algoritm on mõeldud selleks, et ületada käepideme üldkoormus ja lahendada kuhja prahi prügikogumine. Kui objekt on täis, skaneerib kopeerimisalgoritmil põhinev prügikogumine aktiivse objekti juurhulgast ja kopeerib iga aktiivse objekti vabale pinnale (nii et aktiivse objekti mälu vahele ei jääks vabu auke), nii et vaba pind muutub objekti näoks, algne objekti nägu vabaks ja programm eraldab mälu uuele objekti pinnale. Tüüpiline prügikogumise meetod, mis põhineb toimetulekualgoritmil, on stop-and-copy algoritm, mis jagab kuhja objektide ja vaba ala pindadeks ning programm peatab täitmise objekti ja vaba ala nägude vahetamise ajal.
5. Põlvkonnakoguja
![]()
Põlvkondade prügi taaskasutusstrateegia põhineb faktil, etErinevate objektide elutsükkel on erinev。 Seetõttu saavad erineva elutsükliga objektid kasutada erinevaid taaskasutusalgoritme, et parandada taaskasutuse efektiivsust.
Noor põlvkond 1. Kõik äsja genereeritud objektid paigutatakse esmalt nooremale põlvkonnale. Noorema põlvkonna eesmärk on koguda need lühikese elutsükliga esemed võimalikult kiiresti.
2. Uue põlvkonna mälu on jagatud üheks Eedeni piirkonnaks ja kaheks ellujääja (ellujääja0, ellujääja1) tsooniks vastavalt suhtele 8:1:1. Üks Eedeni tsoon, kaks ellujääjate tsooni (üldiselt). Enamik objekte ilmub Edeni piirkonnas. Kui survivor0 ala on samuti täis, kopeeritakse Edeni ala ja Survivor0 ala teise Survivor1 piirkonda, seejärel tühjendatakse Eden ja Survivor0 ala ning Survivor0 ala on tühi ning Survivor0 ala ja Survivor1 ala vahetatakse. See tähendab, et survivor1 ala jääb tühjaks ja nii edasi.
3. Kui ellujääja 1 ala ei ole piisav, et hoida Edeni ja Survivor0 ellujäänud esemeid, salvestatakse ellujäänud esemed otse vanasse ajastusse. Kui vanadus on samuti täis, käivitab see täieliku GC, see tähendab, et uus põlvkond ja vana põlvkond taaskasutatakse
4. Uue põlvkonna GC-d nimetatakse ka Minor GC-ks ning MinorGC sagedus on suhteliselt kõrge (see ei pruugi käivituda, kui Eedeni ala on täis)
Vana põlvkond
1. Objektid, mis on nooremas põlvkonnas pärast N prügi taaskasutust veel elus, paigutatakse vanemasse põlvkonda. Seetõttu võib pidada vana põlvkonda mõnes objektis, millel on pikk elutsükkel.
2. Mälu on ka palju suurem kui uue põlvkonna oma (ligikaudne suhe on 1:2), kui vanaduse mälu on täis, aktiveerub Major GC, st Full GC, Full GC sagedus on suhteliselt madal, vanadusobjekti ellujäämisaeg suhteliselt pikk ja ellujäämismäär kõrge.
Püsiv põlvkond Kasutatakse staatiliste failide, nagu Java klasside, meetodite jms salvestamiseks. Püsivad generatsioonid ei mõjuta prügi kogumist oluliselt, kuid mõned rakendused võivad dünaamiliselt genereerida või kutsuda mõningaid klasse, näiteks Hibernate jne, ning antud juhul tuleb käivitamise ajal seadistada suhteliselt suur püsiv generatsiooniruum, et neid uusi klasse salvestada.
3. GC (prügikoguja)Uue põlvkonna kollektsionääride kasutatavad kollektsionäärid: Serial, PraNew, Parallel Scavenge Vanaduskollektsionääride kasutatavad kollektsionäärid: Serial Vanad, Paralleelvanad, CMS
![]()
Seriaalkoguja (replikatsioonialgoritm) Uue põlvkonna ühekeermelised kollektorid, märgistamine ja puhastamine on ühekeermelised, mille eeliseks on lihtsus ja tõhusus.
Seerialine vana kollektsionäär (sildi viimistluse algoritm) Vana aja ühe niidi kollektsionäär, vana aja versioon seriaalkogujast.
ParNew kollektor (stop-copy algoritm) Uue põlvkonna kollektorit võib pidada mitmelõimelise versioonina Serial Collectorist, millel on parem jõudlus kui Serial mitmetuumalises protsessorikeskkonnas.
Paralleelne scavenge koguja (stop-copy algoritm) Paralleelkollektorid kõrge läbilaskevõime ja tõhusa protsessori kasutamise jaoks. Läbilaskevõime on üldiselt 99% ja läbilaskevõime = kasutaja lõime aeg / (kasutaja lõime aeg + GC lõime aeg). See sobib näiteks taustarakenduste jaoks, mis ei nõua vastavalt suurt interaktsiooni.
Paralleelne vana kollektor (stop-copy algoritm) Vanem versioon Parallel Scavenge kollektorist, paralleelkoguja, läbilaskevõime prioriteediga
CMS (Concurrent Mark Sweep) Collector (Mark-Clean algoritm) Kõrge samaaegsus, madal paus, lühima GC taastamise pausiaja, kõrge protsessori kasutus, kiire reageerimisaeg, lühike pausiaeg ning mitmetuumaline protsessor, mis püüab saavutada kõrget reageerimisaega
4. GC rakendusmehhanismKuna eset on töödeldud erinevates põlvkondades, on ka prügi kogumise ala ja aeg erinevad. On kahte tüüpi GC-d: Scavenge GC ja Full GC.
Scavenge GC Tavaliselt, kui uus objekt genereeritakse ja see ei taotle ruumi Edenis, käivitub Scavenge GC, mis GC-b Edeni ala, puhastab mitteellujäänud objektid ja viib ellujäänud objektid ellujäämisalale. Seejärel sorteeri Survivor kaks tsooni. Sellisel viisil tehakse GC noorema põlvkonna Eedeni piirkonnas ega mõjuta vanemat põlvkonda. Kuna enamik objekte algab Eedeni piirkonnast ja Eedeni piirkonda ei eraldata eriti palju, viiakse Eedeni piirkonna GC läbi sageli. Seetõttu on üldiselt vajalik kasutada kiireid ja tõhusaid algoritme, et Eden võimalikult kiiresti vabaks teha.
Täielik üldarv Korralda kogu virn, sealhulgas noored, püsivad ja püsivad. Täis GC on aeglasem kui Scavenge GC, sest see nõuab kogu kuhja taaskasutust, seega tuleks täis GC-de arvu võimalikult palju vähendada. Suur osa JVM-i häälestusprotsessist on FullGC häälestamine. Täielik GC võib olla põhjustatud järgmistest põhjustest: 1. Tenured on kirjutatud täisväärtuslikuks 2. Perm on kirjutatud täis 3. System.gc() kuvatakse kõnena 4. Heap'i domeeni jaotusstrateegia muutub dünaamiliselt pärast viimast GC-d
5. Java koos GC-ga esineb samuti mälulekke probleeme1. Staatiliste kogumisklasside, nagu HashMap, Vector jne, kasutamine on kõige vastuvõtlikum mälulekketele ning nende staatiliste muutujate elutsükkel on sama mis rakenduse oma, ning kõiki objekte ei saa vabastada, sest neid rakendavad alati Vector ja teised. Staatiline vektor v = uus vektor(); for (int i = 1; i<100; i++) { Objekt o = uus objekt(); v.add(o); o = null; } Selles näites on viide v vektorobjekti jaoks ja viide o objekti jaoks koodivirnas. For tsüklis genereerime pidevalt uusi objekte, lisame need vektoriobjektile ja nullime viite o. Küsimus on, kas kui o-viide tühistatakse, siis kui GC esineb, kas objekt, mille me lõime, saab GC poolt taaskasutada? Vastus on ei. Sest kui GC jälgib viiteid koodivirnas, leiab ta v viidet, ja kui sa jätkad jälgimist, leiad, et mäluruumis on viited objektidele, millele viitavad v viited. See tähendab, et kuigi o-viide on tühjendatud, on objekti objektile veel viiteid, millele ligi pääseb, seega GC ei saa neid vabastada. Kui pärast seda tsüklit ei mõjuta objektobjekt programmi, siis eeldame, et Java programmil on mäluleke. 2. Erinevad ühendused, andmebaasiühendused, võrguühendused, IO-ühendused jne ei näita kõnet lähedal ega taaskasutata GC poolt, mis põhjustab mälulekke. 3. Kuulajate kasutamine võib põhjustada mälulekkeid ka siis, kui kuulajat objekti vabastamisel ei kustutata.
|