Forstå Garbage Collection i AS3

Understanding Garbage Collection i AS3
to
Del
8
Del

Dette Cyber ​​mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av.

Har du noen gang brukt en Flash-applikasjonen og la merke til etterslep i det? Fortsatt vet ikke hvorfor det kule flash spillet kjører sakte på datamaskinen? Hvis du ønsker å vite mer om en mulig årsak til det, så denne artikkelen er for deg.

Vi fant denne awesome forfatteren takket FlashGameLicense.com, stedet å kjøpe og selge Flash spill!
< p>
publiseres Tutorial

Hver noen uker, vi besøker noen av våre lesernes favoritt innlegg fra hele historien til området. Denne opplæringen ble første gang utgitt i juni 2010.



Endelig resultat Forhåndsvisning

La oss ta en titt på det endelige resultatet vi skal jobbe mot:



Trinn 1: En rask gjennomgang Henvise

Før vi kommer inn i den virkelige motivet, må du først vite litt om hvordan forekomster og henviser verker i AS3. Hvis du allerede har lest om det, likevel anbefaler jeg å lese denne lite skritt. På den måten vil all kunnskap være frisk i hodet ditt, og du vil ikke ha problemer med å lese resten av denne Quick Tips!

Opprettelse og referanse forekomster i AS3 er annerledes enn de fleste tror. Den oppretting (eller "skapelse") av noe som skjer bare når koden ber om å opprette et objekt. Vanligvis skjer dette gjennom den "nye" søkeord, men det er også til stede når du bruker en bokstavelig syntaks
eller definere parametere for funksjoner, for eksempel. Eksempler på dette er vist nedenfor:
//forekomsten gjennom "nye" keywordnew Object (); new Array (); new int (); new String (); new Boolean (); new Date (); //oppretting gjennom bokstavelig syntaks {}; []; 5 "Hello world!" true //forekomsten gjennom funksjon parametersprivate funksjon tutExample (parameter1: int, parameter2: Boolean): void

Etter et objekt er opprettet, vil det forbli alene inntil noe refererer det. For å gjøre det, du generelt skape en variabel og bestå objektets verdi til variabelen, slik at den vet hvilket objekt det øyeblikket innehar. Men (og dette er den delen folk flest ikke vet), når du passerer en variabel til en annen variabel, er du ikke lage et nytt objekt. Du er i stedet å opprette en annen kobling til objektet som begge variabler nå holder! Se bildet nedenfor for avklaring:

Bildet forutsetter både Variabel 1 Hotell og Variabel 2
kan holde smiley (dvs. de kan holde samme type). I venstre side, bare finnes Variable en
. Men når vi skaper og satt Variabel 2
til samme verdi på Variable en
, vi er ikke å skape en kobling mellom Variabel 1 Hotell og Variabel 2 product: (øverst til høyre på bildet), i stedet vi skaper en kobling mellom Smiley og Variabel to plakater (nederst til høyre i bildet).

Med denne kunnskapen , kan vi hoppe til Garbage Collector



Trinn 2:. Hver by trenger en Garbage Collector

Det er åpenbart at hver applikasjon trenger en viss mengde minne til å kjøre, så det trenger variabler å holde verdier og bruke dem. Hva er ikke klart, er hvordan programmet håndterer objektene som ikke er nødvendig lenger. Betyr det resirkulere dem? Betyr det slette dem? Later det objektet i minnet til programmet er lukket? Alle tre alternativene kan skje, men her vil vi snakke spesifikt om det andre og tredje funn.

Tenk deg en situasjon der en søknad skaper mye gjenstander når det er initialisert, men når denne perioden ender mer enn halvparten av objekter som er opprettet forbli ubrukt. Hva ville skje hvis de ble forlatt i minnet? De ville sikkert ta mye plass i den, og dermed forårsaker hva folk kaller etterslep
, som er en merkbar nedbremsing i søknaden. De fleste brukere vil ikke liker dette, så vi må unngå det. Hvordan kan vi kode for å gjøre programmet kjøre mer effektivt? Svaret er i Garbage Collector
.

The Garbage Collector er en form for minnehåndtering. Formålet er å eliminere enhver gjenstand som ikke er brukt og er som opptar plass i systemminnet. På denne måten programmet kan kjøres med mimimum minnebruk. La oss se hvordan det fungerer:

Når programmet starter å kjøre, spør den for en mengde minne fra systemet som vil bli brukt av programmet. Programmet starter deretter å fylle dette minnet med all informasjon du trenger; hvert objekt du opprette går inn i den. Men hvis minnebruken blir nær til minne ba i utgangspunktet, kjører Garbage Collector, søker ethvert objekt ikke brukes til å tømme litt plass i minnet. Noen ganger dette fører til litt etterslep i programmet, på grunn av den store belastningen av objektet søking.

I bildet, kan du se minne topper plakater (innringet i grønt). Toppene og plutselig fall er forårsaket av garbage collector, som fungerer når programmet har nådd den ønskede minnebruk (den røde linjen), fjerne alle unødvendige gjenstander



Trinn 3:. Starte SWF Fil

Nå som vi vet hva Garbage Collector kan gjøre for oss, er det på tide å lære å kode for å få alle fordeler av det. Først av alt, må vi vite hvordan Garbage Collector fungerer, i et praktisk syn. I kode, gjenstander bli kvalifisert for Garbage Collection når de blir uoppnåelig. Når et objekt ikke kan nås, forstår koden at det ikke skal brukes lenger, så det må samles.

Actionscript 3 sjekker reachability gjennom søppelrydding røtter
. I øyeblikket et objekt kan ikke nås gjennom en søppelrydding rot, blir det kvalifisert for samlingen. Nedenfor ser du en liste over de viktigste søppelrydding røtter.:.

  • Pakke-nivå og statiske variabler

    Lokale variabler og variabler i omfanget av en utførende metode eller funksjon

    Forekomst variabler fra programmets hoved klassen forekomst eller fra visningslisten.

    For å forstå hvordan objekter håndteres av Garbage Collector, må vi kode og undersøke hva som skjer i eksempel filen. Jeg skal bruke FlashDevelop sin AS3 prosjekt og Flex er kompilatoren, men jeg antar at du kan gjøre det på en hvilken som helst IDE du vil, siden vi ikke kommer til å bruke konkrete ting som bare eksisterer i FlashDevelop. Jeg har bygget en enkel fil med en knapp og tekststruktur. Siden dette ikke er objektiv i denne rask spiss, vil jeg raskt forklare det: når en knapp klikkes, en funksjon branner. Når som helst vi ønsker å vise noe tekst på skjermen, kaller du en funksjon med teksten, og det vises. Det er også et annet tekstfelt for å vise en beskrivelse for knapper.

    Målet vårt eksempel filen er å opprette objekter, slette dem og undersøke hva som skjer med dem etter at de er slettet. Vi trenger en måte å vite om objektet er i live eller ikke, så vil vi legge til en ENTER_FRAME lytter til hver av de objekter, og gjøre dem vise litt tekst med den tiden de har vært i live. Så la oss kode første objekt!

    Jeg laget en morsom smiley bilde for objektene, som en hyllest til Michael James Williams store avoider spillet opplæringen, som også bruker smiley bilder. Hvert objekt vil ha en rekke på hodet, slik at vi kan identifisere den. Dessuten heter jeg det første objektet TheObject1
    , og det andre objektet TheObject2
    , så det vil være lett å skille. La oss gå til koden:
    private Var _theObject1: TheObject1; privat funksjon newObjectSimple1 (e: MouseEvent): void {//Hvis det allerede finnes et objekt skapt, gjør ingenting hvis (_theObject1) tilbake; //Opprett nytt objekt, sett den til den posisjonen den skal være på og legge til visningslisten, slik at vi kan se det ble opprettet _theObject1 = new TheObject1 (); _theObject1.x = 320; _theObject1.y = 280; _theObject1.addEventListener (Event.ENTER_FRAME, changeTextField1); addChild (_theObject1);}

    Det andre objektet ser nesten det samme. Her er det:
    private Var _theObject2: TheObject2; privat funksjon newObjectSimple2 (e: MouseEvent): void {//Hvis det allerede finnes et objekt skapt, gjør ingenting hvis (_theObject2) tilbake; //Opprett nytt objekt, sett den til den posisjonen den skal være på og legge til visningslisten, slik at vi kan se det ble opprettet _theObject2 = new TheObject2 (); _theObject2.x = 400; _theObject2.y = 280; _theObject2.addEventListener (Event.ENTER_FRAME, changeTextField2); addChild (_theObject2);}

    I koden, newObjectSimple1 () Hotell og newObjectSimple2 ()
    er funksjoner som er avfyrt når deres tilhørende knappen klikkes. Disse funksjonene bare lage et objekt og legge den i den vanlige skjermen, så vi vet at det ble opprettet. I tillegg skaper det en ENTER_FRAME
    hendelse lytteren i hvert objekt, som vil gjøre dem vise en melding hvert sekund, så lenge de er aktive. Her er funksjonene:
    privat funksjon changeTextField1 (e: Arrangement): void {//Vårt eksempel kjører på 30fps, så la oss legge 1/30 på hver ramme i tellingen. _objectCount1 + = 0,034; //Sjekker for å se om _objectCount1 har passert ett sekund hvis (int (_objectCount1) > _secondCount1) {//Viser en tekst i skjermbildet displayText ("Object en er i live ..." + int (_objectCount1)); _secondCount1 = int (_objectCount1); }} privat funksjon changeTextField2 (e: Hendelses): void {//Vårt eksempel kjører på 30fps, så la oss legge 1/30 på hver ramme i tellingen. _objectCount2 + = 0,034; //Sjekker for å se om _objectCount2 har passert ett sekund hvis (int (_objectCount2) > _secondCount2) {//Viser en tekst i skjermbildet displayText ("Object to er i live ..." + int (_objectCount2)); _secondCount2 = int (_objectCount2); }}

    Disse funksjonene bare vise en melding på skjermen med tiden gjenstandene har vært i live. Her er en SWF-fil med dagens eksempel:



    Trinn 4: Slette Objekter

    Nå som vi har dekket etableringen av objekter, la oss prøve noe: har du noen gang lurt på hva ville skje hvis du faktisk slette (fjerne alle referanser) et objekt? Betyr det blir søppel samles inn? Det er det vi vil teste nå. Vi skal bygge to sletteknapper, en for hvert objekt. La oss gjøre koden for dem:
    privat funksjon deleteObject1 (e: MouseEvent): void {//Sjekk om _theObject1 virkelig eksisterer før den fjernes fra listen skjermen hvis (_theObject1 & & inneholder (_theObject1)) removeChild (_theObject1 ); //Fjerne alle referanser til objektet (dette er den eneste referansen) _theObject1 = null; //Viser en tekst i skjermen displayText;} private funksjon deleteObject2 (e: MouseEvent): ("Slettet objekt en vellykket!") Void {//Sjekk om _theObject2 virkelig eksisterer før du fjerner den fra displayet listen hvis (_theObject1 & & inneholder (_theObject2)) removeChild (_theObject2); //Fjerne alle referanser til objektet (dette er den eneste referansen) _theObject2 = null; //Viser en tekst i skjermbildet displayText ("Slettet objekt to hell!");}

    La oss ta en titt på SWF nå. Hva tror du vil skje?

    Som du kan se. Hvis du klikker "Create Object1" og deretter "Slett Object1", ikke noe virkelig skjer! Vi kan fortelle koden kjøres, fordi teksten vises på skjermen, men hvorfor ikke objektet blir slettet? Objektet er fortsatt der fordi det ikke ble fjernet. Når vi fjernet alle referanser til det, fortalte vi koden for å gjøre det kvalifisert for søppelrydding, men søppeltømmeren aldri går. Husk at søppeltømmeren vil bare kjøre når minnebruken nærmer seg den forespurte minnet når programmet begynte å kjøre. Det virker fornuftig, men hvordan skal vi teste dette?

    Jeg er sikkert ikke kommer til å skrive et stykke kode for å fylle vår søknad med unyttige gjenstander til minnebruken blir for stor. I stedet vil vi bruke en funksjon for øyeblikket som ikke støttes av Adobe, ifølge Grant Skinner artikkel, som tvinger Garbage Collector å kjøre. På den måten kan vi utløse denne enkle metoden, og se hva som skjer når den går. Også fra nå av vil jeg henvise til Garbage Collector som GC, for enkelhets skyld. Her er funksjonen:
    privat funksjon forceGC (e: MouseEvent): void {try {nytt LocalConnection () koble ('foo');. . ny LocalConnection () koble ('foo'); } Catch (e: *) {} //Viser en tekst i skjermbildet displayText ("----- Søppelrydding utløst -----");}

    Denne enkle funksjonen, som bare skaper to LocalConnection ( ) objekter, er kjent for å tvinge GC å kjøre, så vi vil kalle det når vi ønsker at dette skal skje. Jeg anbefaler ikke å bruke denne funksjonen i en seriøs søknad. Hvis du gjør det for test, er det ingen reelle problemer, men hvis det er for et program som vil bli distribuert til folk, dette er ikke en god funksjon å bruke, siden det kan medføre negative effekter.

    Det jeg anbefaler for tilfeller som dette er at du bare la GC løpe i sitt eget tempo. Ikke prøv å tvinge den. I stedet fokuserer på koding effektivt, slik at minneproblemer ikke skje (vi vil dekke dette i trinn 6). Nå, la oss ta en titt på vårt eksempel SWF på nytt, og klikk på "Collect Garbage" -knappen etter opprette og slette et objekt.

    Har du testet filen? Det fungerte! Du kan se at nå, etter å ha slettet et objekt og utløser GC, fjerner det objektet! Legg merke til at hvis du ikke sletter objektet og kaller GC, vil ingenting skje, siden det fortsatt er en referanse til det objektet i koden. Nå, hva om vi prøver å holde to referanser til et objekt og fjerne en av dem



    Trinn 5: Opprette En annen referanse

    Nå som vi har bevist at GC fungerer nøyaktig som vi ønsket, la oss prøve noe annet: knytte en annen referanse til et objekt (Object1) og fjerne det opprinnelige. Først må vi lage en funksjon for å koble til og fra en referanse til objektet vår. La oss gjøre det:
    privat funksjon saveObject1 (e: MouseEvent): void {//_onSave er en boolsk å sjekke om vi skulle koble eller frakoble referansen if (_onSave) {//Hvis det ikke er gjenstand for å lagre, gjøre ingenting if (! _theObject1) {//Viser en tekst i skjermbildet displayText ("Det er ikke noe objekt en å spare!"); komme tilbake; } //En ny variabel for å holde en annen referanse til Object1 _theSavedObject = _theObject1; //Viser en tekst i skjermbildet displayText ("Saved objekt en vellykket!"); //På neste gang denne funksjonen kjører, frakoble den, siden vi bare knyttet _onSave = false; } Else {//Fjerne referanse til det _theSavedObject = null; //Viser en tekst i skjermbildet displayText ("Ulagret objekt en vellykket!"); //På neste gang denne funksjonen kjører, koble det, siden vi bare ulenket _onSave = true; }}

    Hvis vi teste våre swf nå, vil vi legge merke til at hvis vi skaper Object1, deretter lagre den, slette den og tvinge GC å kjøre, vil ingenting skje. Det er fordi nå, selv om vi fjernet den "originale" linken til objektet, er det fortsatt en annen referanse til det, som holder det fra å være kvalifisert for søppelrydding. Dette er i utgangspunktet alt du trenger å vite om Garbage Collector. Det er ikke et mysterium, tross alt. men hvordan vi bruker dette til vår nåværende miljø? Hvordan kan vi bruke denne kunnskapen til å hindre vår søknad fra å kjøre sakte? Dette er hva Trinn 6 vil vise oss: hvordan du skal bruke dette i reelle eksempler



    Trinn 6:. Making Your Kode Effektiv

    Nå for den beste delen: å lage din kode arbeid med GC effektivt! Dette trinnet vil gi nyttig informasjon som du bør holde for hele livet - lagre det riktig! Først vil jeg gjerne presentere en ny måte å bygge dine gjenstander i programmet. Det er en enkel, men effektiv måte å samarbeide med GC. På denne måten introduserer to enkle klasser, som kan utvides til andre, når du forstår hva det gjør

    Ideen om denne måten er å implementere en funksjon -. Kalt ødelegge () - på hvert objekt som du oppretter, og kaller det hver gang du er ferdig med et objekt. Funksjonen inneholder all koden er nødvendig for å fjerne alle referanser til og fra objektet (unntatt referansen som ble brukt til å kalle funksjonen), slik at du sørge for at objektet forlater søknaden din helt isolert, og er lett kjennelig på GC. Grunnen til dette er forklart i det neste trinnet. La oss se på den generelle koden for funksjonen:
    //Lag dette i hvert objekt du usepublic funksjon ødelegge (): void {//Fjern hendelsen lyttere //fjerne noe i displayet liste //Clear referanser til andre objekter , så det blir helt isolert} //... //Når du ønsker å fjerne objektet, gjør dette: theObject.destroy (); //Og så null siste referanse til ittheObject = null;

    I denne funksjonen , må du fjerne alt fra objektet, så det er fortsatt isolert i søknaden. Når du har gjort det, vil det være lettere for GC for å lokalisere og fjerne gjenstanden. Nå la oss se på noen av de situasjoner der de fleste minnefeil skje:

    Objekter som bare brukes i et intervall på henrettelse: Vær forsiktig med disse seg, som de kan være de som bruker en mye minne. Disse stedene eksisterer bare for en viss periode (for eksempel til å lagre verdier når en funksjon går) og de er ikke vist så ofte. Husk å fjerne alle referanser til dem etter at du er ferdig med dem, ellers kan du ha mange av dem i programmet, og bare tar plass i minnet. Husk at hvis du oppretter en masse referanser til dem, må du eliminere hver enkelt gjennom ødelegge ()
    funksjon

    Objekter igjen i visningslisten. Alltid fjerne et objekt fra visningslisten hvis du ønsker å slette den. Displayet listen er en av de søppelrydding røtter
    (husker det?) Og så er det veldig viktig at du holder gjenstander bort fra det når du fjerner dem.

  • Stage, foreldre og rot referanser: hvis du liker å bruke mye disse egenskapene, må du huske å fjerne dem når du er ferdig. Hvis mange av dine objekter har en referanse til disse, kan du være i trøbbel

    Hendelses lyttere: noen ganger referansen som holder gjenstander fra å få samlet er en hendelse lytteren. Husk å fjerne dem, eller bruke dem som svake lyttere, om nødvendig

    Arrays og vektorer. Noen ganger dine matriser og vektorer kan ha andre objekter, forlater referanser innen dem som du kanskje ikke er klar over. Vær forsiktig med matriser og vektorer


    Trinn 7: The Island of Referanser

    Selv arbeider med GC er stor, det er ikke perfekt. Du må ta hensyn til hva du gjør, ellers dårlige ting kan skje med søknaden. Jeg vil gjerne vise et problem som kan dukke opp hvis du ikke følger alle de nødvendige skritt for å gjøre din kode arbeidet med GC riktig.

    Noen ganger, hvis du ikke kan fjerne alle referanser til og fra et objekt, kan du ha dette problemet, spesielt hvis du kobler en rekke gjenstander sammen i søknaden din. Noen ganger kan en eneste referanse igjen være nok for at dette skal skje. Alle objektene danner en øy av referanser, der alle objekter er koblet til andre, ikke slik at GC for å fjerne dem

    Når GC løper, utfører det to enkle oppgaver for å se etter gjenstander som skal slettes. En av disse oppgavene er å telle hvor mange referanser hvert objekt har. Alle objekter med 0 referanser blir innsamlet samtidig. Den andre oppgaven er å sjekke om det er noen liten haug med gjenstander som lenker til hverandre, men kan ikke nås, og dermed sløse minne. Sjekk bildet:

    Som du kan se, den grønne gjenstander kan ikke nås, men deres referansetelling er 1. GC utfører andre oppgaver for å se etter denne del av objekter og fjerner dem alle. Imidlertid, når del er for stor, GC "gir seg" på kontroll og forutsetter gjenstandene kan nås. Nå forestille seg hvis du har noe sånt som at:

    Dette er øya referanser. Det ville ta mye minne fra systemet, og vil ikke bli samlet inn av GC på grunn av kompleksiteten av det. Det høres ganske ille, ikke sant? Det kan lett unngås, skjønt. Bare sørg for at du har fjernet alle referanser til og fra et objekt, og deretter skumle ting som det vil ikke skje!



    Konklusjon

    Dette er det for nå. I denne hurtig Tips lærte vi at vi kan gjøre vår kode bedre og mer effektiv for å redusere etterslep og minneproblemer, og dermed gjør det mer stabilt. For å gjøre dette, må vi forstå hvordan refererer gjenstander jobbe i AS3, og hvordan du kan dra nytte av dem til å gjøre GC arbeidet ordentlig i søknaden vår. Til tross for at vi kan gjøre vårt program bedre, må vi være forsiktig når du gjør det - ellers kan det bli enda Messier og tregere

    Jeg håper du likte denne enkle tipset. Hvis du har noen spørsmål, send en kommentar nedenfor
    !