1. Šiukšlių perdirbimo mechanizmo reikšmė Pastebimas "Java" kalbos bruožas yra šiukšlių surinkimo mechanizmo įdiegimas, kuris išsprendžia labiausiai varginančią C++ programuotojų atminties valdymo problemą, kad "Java" programuotojams nebereikėtų galvoti apie atminties valdymą rašant programas. Dėl šiukšlių surinkimo mechanizmo "Java" objektai nebeturi "apimties" sąvokos, tik objekto nuoroda turi "taikymo sritį".Šiukšlių surinkimas gali veiksmingai užkirsti kelią atminties nutekėjimui ir efektyviai naudoti nenaudojamą atmintį.
ps:内存泄露是指该内存空间使用完毕之后未回收,在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度,我们有时也将其称为“对象游离”。
2. Šiukšlių surinkimo mechanizmų algoritmai Java kalbos specifikacija aiškiai nenurodo, kokį šiukšlių surinkimo algoritmą naudoti JVM, tačiau bet koks šiukšlių surinkimo algoritmas paprastai turi atlikti du pagrindinius dalykus: (1) rasti nenaudingus informacijos objektus; (2) Susigrąžinkite atminties vietą, kurią užima nenaudingi objektai, kad programa vėl galėtų naudoti vietą.
1. Nuorodų skaičiavimo kolektorius 1.1 Algoritmo analizė
Nuorodų skaičiavimas yra ankstyva šiukšlių surinkėjų strategija. Taikant šį metodą, yra kiekvieno krūvos objekto egzemplioriaus nuorodų skaičius. Kai sukuriamas objektas ir objekto egzempliorius priskiriamas kintamajam, kintamųjų skaičius nustatomas į 1. Kai bet kuris kitas kintamasis priskiriamas kaip nuoroda į šį objektą, skaičius pridedamas iš 1 (a = b, tada objekto egzemplioriaus, kurį nurodo b, skaitiklis yra +1), tačiau kai nuoroda į objekto egzempliorių viršija savo gyvavimo laiką arba nustatoma nauja reikšmė, objekto egzemplioriaus nuorodos skaitiklis atimamas iš 1. Bet koks objekto, kurio atskaitos skaitiklis yra 0, egzempliorius gali būti renkamas kaip šiukšlė. Kai objekto egzempliorius yra šiukšlių surinkimas, bet kurio objekto egzemplioriaus nuorodų skaitiklis yra minus 1. 1.2 Privalumai ir trūkumai Nuopelnus:
Nuorodų skaičiaus kolektorius gali būti vykdomas labai greitai, įsipynęs į programos vykdymą. Tai naudinga realiojo laiko aplinkoje, kur programų nereikia pertraukti ilgą laiką. Trūkumas:
Žiedinių nuorodų aptikti negalima. *Jei pirminis objektas turi nuorodą į antrinį objektą, antrinis objektas savo ruožtu nurodo pirminį objektą. Tokiu būdu jų citatų skaičius niekada negali būti 0. 1.3 Nuorodų skaičiavimo algoritmas negali išspręsti žiedinės nuorodos problemos, pavyzdžiui:
/** * 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; }} Paskutiniuose dviejuose sakiniuose objektas1 ir objektas2 priskiriami nuliui, o tai reiškia, kad objektai, į kuriuos nurodo objektas1 ir objektas2, nebegali būti pasiekiami, tačiau dėl to, kad jie nurodo vienas kitą, jų atskaitos skaitikliai nėra 0, todėl šiukšlių surinkėjas niekada jų neperdirbs.
2. Sekimo kolektorius arba žymėjimo ir šlavimo algoritmas 2.1 Šaknies paieškos algoritmas
Šaknies paieškos algoritmas yra įvestas iš grafų teorijos diskrečioje matematikoje, programa visus nuorodų ryšius laiko grafiku, pradedant nuo mazgo GC ROOT, ieškant atitinkamo atskaitos mazgo, suradus šį mazgą, toliau ieškant šio mazgo atskaitos mazgo, kai ieškoma visų atskaitos mazgų, likę mazgai laikomi nenurodytais mazgais, tai yra nenaudingais mazgais. Java, kuri gali būti naudojama kaip GC šaknis 1. Virtualios mašinos rietuvėje nurodyti objektai (vietinių kintamųjų lentelė) 2. Objektas, kurį nurodo statinis atributas metodo srityje 3. Objektas, kurį nurodo konstanta metodo srityje 4. Nurodyti objektai vietiniame metodų krūvoje (vietiniai objektai)
2.2 Sekimo algoritmo schema
![]()
2.3 Žymeklių išvalymo algoritmo analizė
Žymų valymo algoritmas nuskaito iš šaknų kolekcijos, pažymi išlikusius objektus ir nuskaito visą erdvę, ar nėra pažymėtų objektų, kuriuos reikia perdirbti, kaip parodyta aukščiau esančiame paveikslėlyje. Žymių išvalymo algoritmui nereikia perkelti objektų, o apdoroja tik neišlikusius objektus, o tai yra labai efektyvu, kai yra daug išlikusių objektų, tačiau kadangi žymių išvalymo algoritmas tiesiogiai perdirba neišlikusius objektus, tai sukels atminties fragmentaciją.
3. Tankinimo algoritmas arba etikečių apdailos algoritmas
![]()
Žymos užbaigimo algoritmas naudoja tą patį metodą kaip ir žymos išvalymo algoritmas objektams žymėti, tačiau jis skiriasi išvalant, atgavus neišlikusių objektų užimtą vietą, jis perkels visus išlikusius objektus į laisvą vietą kairiajame gale ir atnaujins atitinkamą žymeklį. Žymos užbaigimo algoritmas yra pagrįstas žymų išvalymo algoritmu ir perkelia objektus, todėl jis yra brangesnis, tačiau išsprendžia atminties fragmentacijos problemą. Įgyvendinant kolektorius, pagrįstus tankinimo algoritmu, paprastai pridedamos rankenos ir rankenų lentelės.
4. Kopijavimo algoritmas (tankinimo kolektorius)
![]()
Algoritmas siūlomas įveikti rankenos viršutinę dalį ir išspręsti krūvos šiukšlių surinkimą. Kai objektas pilnas, šiukšlių surinkimas, pagrįstas kopijavimo algoritmu, nuskaito aktyvų objektą iš šaknų rinkinio ir nukopijuoja kiekvieną aktyvų objektą į laisvą veidą (kad tarp aktyvaus objekto užimtos atminties nebūtų laisvų skylių), kad laisvas paviršius taptų objekto paviršiumi, originalus objekto paviršius taptų laisvu veidu, o programa paskirstytų atmintį naujame objekto paviršiuje. Tipiškas šiukšlių surinkimas, pagrįstas susidorojimo algoritmu, yra sustabdymo ir kopijavimo algoritmas, kuris padalija krūvą į objektų veidus ir laisvos srities veidus, o programa pristabdo vykdymą perjungiant objektų veidus ir laisvos srities veidus.
5. Kartų kolekcionierius
![]()
Kartų šiukšlių perdirbimo strategija grindžiama tuo, kadSkirtingų objektų gyvavimo ciklas yra skirtingas。 Todėl skirtingo gyvavimo ciklo objektai gali pritaikyti skirtingus perdirbimo algoritmus, kad pagerintų perdirbimo efektyvumą.
Jaunoji karta 1. Visi naujai sukurti objektai pirmiausia priskiriami jaunajai kartai. Jaunosios kartos tikslas yra kuo greičiau surinkti tuos objektus, kurių gyvavimo ciklas yra trumpas.
2. Naujos kartos atmintis yra padalinta į vieną Edeno regioną ir dvi išgyvenusiųjų (survivor0, survivor1) zonas santykiu 8:1:1. Viena Edeno zona, dvi Survivor zonos (apskritai). Dauguma objektų neršia Edeno srityje. Kai survivor0 sritis taip pat yra pilna, eden sritis ir survivor 0 sritis nukopijuojama į kitą survivor1 sritį, tada eden ir survivor0 sritis yra ištuštinama, ir tada survivor0 sritis yra tuščia, ir tada survivor0 sritis ir survivor1 sritis yra apsikeista. Tai yra, palikite maitintojo1 sritį tuščią ir pan.
3. Kai išgyvenusio 1 ploto nepakanka išlikusiems Edeno ir Survivor0 objektams laikyti, išlikę objektai saugomi tiesiai į senąją erą. Jei senatvė taip pat bus pilna, tai suaktyvins pilną GC, tai yra, nauja karta ir senoji karta bus perdirbta
4. Naujos kartos GC taip pat vadinamas Minor GC, o MinorGC dažnis yra gana didelis (jis nebūtinai suveikia, kai Edeno sritis yra pilna)
Senoji karta
1. Objektai, kurie vis dar gyvi po to, kai patyrė N šiukšlių perdirbimą jaunoje kartoje, bus dedami į vyresniąją kartą. Todėl galima manyti, kad senoji karta saugoma kai kuriuose objektuose, turinčiuose ilgą gyvavimo ciklą.
2. Atmintis taip pat yra daug didesnė nei naujos kartos (apytikslis santykis yra 1:2), kai senatvės atmintis yra pilna, suveikia pagrindinis GC, tai yra pilnas GC, viso GC dažnis yra palyginti mažas, senatvės objekto išgyvenimo laikas yra gana ilgas, o išgyvenamumo rodiklis yra didelis.
Nuolatinė karta Naudojamas statiniams failams, pvz., Java klasėms, metodams ir kt., saugoti. Nuolatinės kartos neturi reikšmingos įtakos šiukšlių surinkimui, tačiau kai kurios programos gali dinamiškai generuoti arba iškviesti kai kurias klases, pvz., Hibernate ir kt., ir šiuo atveju reikia nustatyti gana didelę nuolatinę generavimo erdvę, kad būtų galima saugoti šias naujas klases vykdymo metu.
3. GC (šiukšlių surinkėjas)Naujos kartos kolektorių naudojami kolektoriai: Serial, PraNew, Parallel Scavenge Kolekcionieriai, kuriuos naudoja senatvės kolekcionieriai: serijiniai seni, lygiagrečiai seni, CMS
![]()
Serijinis kolektorius (replikacijos algoritmas) Naujos kartos vieno sriegio kolektoriai, žymėjimas ir valymas yra vieno sriegio, o pranašumas yra paprastas ir efektyvus.
Serijinis senas kolektorius (etikečių apdailos algoritmas) Senatvės vieno sriegio kolektorius, serijinio kolektoriaus senatvės versija.
ParNew kolektorius (stop-copy algoritmas) Naujos kartos kolektorius gali būti laikomas kelių gijų serijinio kolektoriaus versija, kuri pasižymi geresniu našumu nei "Serial" kelių branduolių procesoriaus aplinkoje.
Lygiagretus Scavenge Collector (Stop-Copy algoritmas) Lygiagrečiai kolektoriai dideliam pralaidumui ir efektyviam procesoriaus panaudojimui. Pralaidumas paprastai yra 99%, o pralaidumas = vartotojo gijos laikas / (vartotojo gijos laikas + GC gijos laikas). Jis tinka tokiems scenarijams kaip foninės programos, kurioms nereikia atitinkamai didelės sąveikos.
Lygiagretus senas kolektorius (Stop-Copy algoritmas) Senesnė "Parallel Scavenge" kolektoriaus versija, lygiagretus kolektorius, su pralaidumo prioritetu
CMS (Concurrent Mark Sweep) kolektorius (Mark-Clean algoritmas) Didelis sutapimas, maža pauzė, trumpiausias GC atkūrimo pauzės laikas, didelis procesoriaus naudojimas, greitas atsako laikas, trumpas pauzės laikas ir kelių branduolių procesorius, siekiantis ilgo atsako laiko
4. GC įgyvendinimo mechanizmasKadangi objektas buvo apdorojamas skirtingomis kartomis, skiriasi ir šiukšlių surinkimo plotas bei laikas. Yra dviejų tipų GC: Scavenge GC ir Full GC.
Scavenge GC Paprastai, kai sugeneruojamas naujas objektas ir nepavyksta kreiptis dėl vietos Edene, suveikia Scavenge GC, kuris GC Edeno sritį, išvalys neišlikusius objektus ir perkels išlikusius objektus į Survivor sritį. Tada surūšiuokite dvi "Survivor" zonas. GC tokiu būdu atliekamas jaunosios kartos Edeno srityje ir neturi įtakos vyresniajai kartai. Kadangi dauguma objektų prasideda nuo Edeno srities, o Edeno sritis nėra skiriama labai daug, Edeno srities GC atliekamas dažnai. Todėl paprastai čia reikia naudoti greitus ir efektyvius algoritmus, kad Edenas būtų kuo greičiau nemokamas.
Visas GC Sutvarkykite visą krūvą, įskaitant jaunus, etatinius ir permę. Full GC yra lėtesnis nei Scavenge GC, nes reikia perdirbti visą krūvą, todėl Full GC skaičius turėtų būti kiek įmanoma sumažintas. Didelė JVM derinimo proceso dalis yra FullGC derinimas. Pilną GC gali sukelti šios priežastys: 1. Kadencija parašyta pilna 2. Permė parašyta pilna 3. System.gc() rodomas kaip iškvietimas 4. Heap domenų paskirstymo strategija dinamiškai keičiasi po paskutinio GC
5. "Java" su GC taip pat turės atminties nutekėjimo problemų1. Statinių rinkimo klasių, tokių kaip "HashMap", "Vector" ir kt., naudojimas yra labiausiai linkęs į atminties nutekėjimą, o šių statinių kintamųjų gyvavimo ciklas yra toks pat kaip programos, o visų objektų negalima išleisti, nes juos visada pritaikys "Vector" ir kiti. Statinis vektorius v = naujas vektorius (); for (int i = 1; I<100; i++) { Objektas o = naujas objektas(); v.add(o); o = nulinis; } Šiame pavyzdyje kodo krūvoje yra nuoroda v objektui Vector ir nuoroda o objektui Object. Cikle For nuolat generuojame naujus objektus, tada pridedame juos prie Vector objekto ir panaikiname o nuorodą. Kyla klausimas, kai o nuoroda yra anuliuota, jei atsiranda GC, ar mūsų sukurtas objekto objektas gali būti perdirbtas GC? Atsakymas yra ne. Nes kai GC seka nuorodas kodų krūvoje, jis randa v nuorodas, o jei toliau seksite, pamatysite, kad atminties erdvėje yra nuorodų į objekto objektus, kuriuos nurodo v nuorodos. Tai reiškia, kad net jei o nuoroda buvo ištuštinta, vis tiek yra kitų nuorodų į objektą, kurias galima pasiekti, todėl GC negali jų išlaisvinti. Jei po šio ciklo objekto objektas neturi įtakos programai, tada darome prielaidą, kad "Java" programa turi atminties nutekėjimą. 2. Įvairūs ryšiai, duomenų bazių ryšiai, tinklo ryšiai, IO ryšiai ir kt. nerodo skambučio arti uždarymo ir GC jų neperdirba, todėl nuteka atmintis. 3. Klausytojų naudojimas taip pat gali sukelti atminties nutekėjimą, kai klausytojas neištrinamas atleidžiant objektą.
|