1. Betydelsen av sopåtervinningsmekanismen En anmärkningsvärd egenskap hos Java-språket är införandet av en skräpsamlingsmekanism, som löser det mest besvärliga minneshanteringsproblemet för C++-programmerare, så att Java-programmerare inte längre behöver tänka på minneshantering när de skriver program. På grund av skräpsamlingsmekanismen har objekt i Java inte längre begreppet "scope", endast objektets referens har ett "scope".Garbage Collection kan effektivt förhindra minnesläckage och effektivt använda inaktivt minne.
ps:内存泄露是指该内存空间使用完毕之后未回收,在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度,我们有时也将其称为“对象游离”。
2. Algoritmer i sophämtningsmekanismer Java-språkspecifikationen specificerar inte uttryckligen vilken skräpsamlingsalgoritm som ska användas i JVM, men alla skräpsamlingsalgoritmer behöver generellt göra två grundläggande saker: (1) hitta värdelösa informationsobjekt; (2) Återta minnesutrymmet som upptas av värdelösa objekt, så att utrymmet kan användas igen av programmet.
1. Referensräkningsinsamlare 1.1 Algoritmanalys
Referensräkning är en tidig strategi inom sophämtare. I denna metod finns det en referensräkning för varje objektinstans i heapen. När ett objekt skapas och objektinstansen tilldelas en variabel, sätts variabelantalet till 1. När någon annan variabel tilldelas som referens till detta objekt adderas räkningen med 1 (a = b, då är räknaren för objektinstansen som refereras till av b +1), men när en referens till en objektinstans har överskridit sin livslängd eller sätts till ett nytt värde, subtraheras referensräknaren för objektinstansen med 1. Varje instans av ett objekt med referensräknaren 0 kan samlas in som skräp. När en objektinstans samlas in i skräphämta är referensräknaren för varje objektinstans den refererar till minus 1. 1.2 Fördelar och nackdelar Förtjänst:
Referensräkningssamlaren kan köras mycket snabbt, integrerad i programmets körning. Det är fördelaktigt i realtidsmiljöer där program inte behöver avbrytas under långa perioder. Brist:
Cirkulära referenser kan inte upptäckas. *Om föräldraobjektet har en referens till ett barnobjekt, refererar barnobjektet i sin tur till förälderobjektet. På så sätt kan deras citationsantal aldrig vara 0. 1.3 Referensräkningsalgoritmen kan inte lösa det cirkulära referensproblemet, till exempel:
/** * 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; }} De två sista meningarna tilldelar objekt1 och objekt2 till null, vilket innebär att objekt1 och objekt2 inte längre kan nås, men eftersom de refererar till varandra är deras referensräknare inte 0, så skräpsamlaren kommer aldrig att återanvända dem.
2. Spårningsinsamlare eller mark-och-svep-algoritm 2.1 Rotsökningsalgoritm
Rotsökningsalgoritmen introduceras från grafteori inom diskret matematik, programmet betraktar alla referensrelationer som en graf, med start från en nod GC ROOT, letar efter motsvarande referensnod, efter att ha hittat denna nod, fortsätter man att leta efter referensnoden för denna nod, när alla referensnoder söks, betraktas de återstående noderna som orefererade noder, det vill säga värdelösa noder. Java som kan användas som GC-rot 1. Objekt som refereras i den virtuella maskinstacken (tabell för lokala variabler) 2. Objektet som refereras av det statiska attributet i metodområdet 3. Objektet som refereras av konstanten i metodområdet 4. Refererade objekt i den lokala metodstacken (Native Objects)
2.2 Schematiskt diagram över spårningsalgoritmen
![]()
2.3 Analys av markörrensningsalgoritm
Tag-purge-algoritmen skannar från rotsamlingen, markerar de överlevande objekten och skannar sedan hela utrymmet efter otaggade objekt att återvinna, som visas i figuren ovan. Tag-purge-algoritmen behöver inte flytta objekt och bearbetar endast icke-överlevande objekt, vilket är extremt effektivt när det finns många överlevande objekt, men eftersom tag-purge-algoritmen direkt återvinner icke-överlevande objekt orsakar det minnesfragmentering.
3. Kompakteringsalgoritm eller etikettfinishalgoritm
![]()
Tag-finish-algoritmen använder samma metod som tag-clear-algoritmen för att märka objekt, men den skiljer sig vid rensning; efter att ha återtagit utrymmet som upptas av icke-överlevande objekt flyttar den alla överlevande objekt till det lediga utrymmet på vänster sida och uppdaterar motsvarande pekare. Tag-finish-algoritmen baseras på tag-purge-algoritmen och flyttar objekt, så den är dyrare, men den löser problemet med minnesfragmentering. Vid implementeringen av collectors baserat på Compacting-algoritmen läggs handtags- och handtagstabeller vanligtvis till.
4. Kopieringsalgoritm (kompakteringsinsamlare)
![]()
Algoritmen föreslås för att övervinna handtagets overhead och lösa skräpsamlingen av heap-debris. När objektet är fullt skannar skräpsamlingen baserad på kopieringsalgoritmen det aktiva objektet från rotmängden och kopierar varje aktivt objekt till den fria ytan (så att det inte finns några fria luckor mellan minnet som det aktiva objektet upptar), så att den fria ytan blir objektets yta, den ursprungliga objektytan blir den fria ytan, och programmet allokerar minne till den nya objektytan. En typisk skräpsamling baserad på coping-algoritmen är stop-and-copy-algoritmen, som delar upp heapen i objektytor och fria ytor, och programmet pausar exekveringen under växlingen mellan objektytor och fria ytor.
5. Generationssamlare
![]()
Den generationsöverskridande strategin för avfallsåtervinning bygger på attLivscykeln för olika objekt är olika。 Därför kan föremål med olika livscykler anta olika återvinningsalgoritmer för att förbättra återvinningseffektiviteten.
Ung generation 1. Alla nygenererade objekt placeras först i den yngre generationen. Målet för den yngre generationen är att samla dessa föremål med en kort livscykel så snabbt som möjligt.
2. Den nya generationens minne delas in i en Eden-region och två överlevandezoner (överlevande0, överlevande1) enligt förhållandet 8:1:1. En Eden-zon, två överlevnadszoner (generellt). De flesta objekten spawnas i Eden-området. När survivor0-området också är fullt kopieras eden-området och survivor 0-området till ett annat survivor1-område, och sedan töms eden- och survivor0-området, och survivor0-området är tomt, och survivor0-området och survivor1-området byts ut. Det vill säga, håll survivor1-området tomt, och så vidare.
3. När området Survivor 1 inte räcker för att lagra de överlevande föremålen från Eden och Survivor0, lagras de överlevande objekten direkt till den gamla eran. Om ålderdomen också är full, kommer det att utlösa en fullständig GC, det vill säga den nya generationen och den gamla generationen kommer att återvinnas
4. Den nya generationens GC kallas också Minor GC, och frekvensen av MinorGC är relativt hög (den utlöses inte nödvändigtvis när Eden-området är fullt)
Gamla generationen
1. Föremål som fortfarande lever efter att ha upplevt N-avfallsåtervinning hos den yngre generationen kommer att placeras i den äldre generationen. Därför kan man betrakta att den gamla generationen lagras i vissa objekt med lång livscykel.
2. Minnet är också mycket större än den nya generationens (det ungefärliga förhållandet är 1:2), när minnet av ålderdomen är fullt, den stora GC utlöses, det vill säga Full GC, är frekvensen av Full GC relativt låg, överlevnadstiden för det gamla objektet är relativt lång och överlevnadsgraden är hög.
Permanent Generation Används för att lagra statiska filer, såsom Java-klasser, metoder osv. Persistenta genereringar har ingen betydande påverkan på skräpsamling, men vissa applikationer kan dynamiskt generera eller anropa vissa klasser, såsom Hibernate med mera, och i detta fall behöver ett relativt stort persistent generationsutrymme ställas in för att lagra dessa nya klasser under körningen.
3. GC (Sophämtare)Samlare som används av den nya generationens samlare: Serial, PraNew, Parallel Scavenge Samlare som används av Old Age Collectors: Serial Old, Parallel Old, CMS
![]()
Seriell samlare (replikationsalgoritm) Den nya generationen av enkeltrådade samlare, märkning och rengöring är enkeltrådade, med fördelen att vara enkla och effektiva.
Seriell gammal samlare (etikett-finish-algoritm) Gammal entrådad samlare, gammal version av seriell samlare.
ParNew-samlare (stop-copy-algoritm) Den nya generationens samlare kan betraktas som en flertrådad version av Serial-kollektoren, som har bättre prestanda än Seriell-kollektoren i en flerkärnig CPU-miljö.
Parallell Scavenge Collector (Stop-copy Algorithm) Parallella samlare för hög genomströmning och effektiv CPU-användning. Genomströmningen är generellt 99 %, och genomströmningen = användartrådtid / (användartrådtid + GC-trådtid). Den är lämplig för scenarier som bakgrundsapplikationer som inte kräver motsvarande hög interaktion.
Parallell gammal samlare (stop-copy algoritm) En äldre version av Parallel Scavenge-samlaren, en parallell kollektor, med genomströmningsprioritet
CMS (Concurrent Mark Sweep) Collector (Mark-Clean-algoritm) Hög samtidighet, låg paus, jakt på kortaste paus för GC-återhämtning, hög CPU-användning, snabb svarstid, kort paustid och flerkärnig CPU som strävar efter hög svarstid
4. Implementeringsmekanismen för GCEftersom objektet har bearbetats i olika generationer är området och tiden för sophämtning också olika. Det finns två typer av GC: Scavenge GC och Full GC.
Scavenge GC Normalt, när ett nytt objekt genereras och inte kan ansöka om utrymme i Eden, triggas Scavenge GC, vilket GC:ar Eden-området, rensar icke-överlevande objekt och flyttar de överlevande objekten till Survivor-området. Sedan sortera de två zonerna av Survivor. GC utförs på detta sätt i Eden-området för den yngre generationen och påverkar inte den äldre generationen. Eftersom de flesta objekt börjar i Eden-området och Eden-området inte tilldelas särskilt mycket, utförs GC av Eden-området ofta. Därför är det generellt nödvändigt att använda snabba och effektiva algoritmer här för att göra Eden gratis så snart som möjligt.
Full GC Organisera hela högen, inklusive Young, Tenured och Perm. Full GC är långsammare än Scavenge GC eftersom det kräver att hela högen återvinns, så antalet Full GCs bör minskas så mycket som möjligt. En stor del av JVM-stämningsprocessen är trimningen av FullGC. Full GC kan orsakas av följande skäl: 1. Tenured är fullskriven 2. Perm skrivs full 3. System.gc() visas som ett samtal 4. Heaps domänallokeringsstrategi förändras dynamiskt efter den senaste GC
5. Java med GC kommer också att ha minnesläckageproblem1. Användningen av statiska samlingsklasser som HashMap, Vector, etc. är mest benägen för minnesläckage, och livscykeln för dessa statiska variabler är densamma som för applikationen, och alla objekt kan inte släppas eftersom de alltid kommer att tillämpas av Vector och andra. Statisk vektor v = ny vektor(); för (int i = 1; i<100; i++) { Objekt o = nytt objekt(); v.add(o); o = null; } I detta exempel finns det en referens v för Vector-objektet och en referens o för Object-objektet i kodstacken. I For-loopen fortsätter vi att generera nya objekt, sedan lägger vi till dem i Vector-objektet och sedan nullifierar o-referensen. Frågan är, när o-referensen nullifieras, om GC inträffar, kan då objektet Object vi skapade återvinnas av GC? Svaret är nej. För när GC spårar referenser i kodstacken hittar den v-referenser, och om du fortsätter spåra ner kommer du att upptäcka att det finns referenser till objektobjekt i minnesutrymmet som v-referenser pekar på. Detta innebär att även om o-referensen har tömmts, finns det fortfarande andra referenser till Objektobjektet som kan nås, så GC kan inte frigöra dem. Om objektet efter denna loop inte påverkar programmet, antar vi att Java-programmet har en minnesläcka. 2. Olika anslutningar, databasanslutningar, nätverksanslutningar, IO-anslutningar etc. visar inte samtalet nära stängt och återanvänds inte av GC, vilket leder till minnesläckage. 3. Användningen av lyssnare kan också orsaka minnesläckage när lyssnaren inte raderas när objektet släpps.
|