Nybörjarefråga igen :) .NET Framework tar hand om att ta "död" på instanser till objekt mha det sk Garbage Collection. Att sätta en objektreferens till Nothing i VB (null i C#) talar om för Garbage Collectorn att det är OK att ta bort objektreferensen. Vill man avlasta Garbage Collectorn och hjälpa den på traven, kan man implementera ett MS pattern kallat Dispose/Finalize i sina egna objekt. Denna lösning innebär att man städar undan referenser för det specifika objektet i fråga. Om du utnyttjar ett .NET-objekt, t ex DataSet, som har en metod med namn Dispose eller Close, så bör du anropa denna när du har använt objektet färdigt. Objektet har då detta pattern implementerat Notera att man inte behöver sätta till Nothing för att Garbage Collectorn skall städa bort ett objekt och att Dispose inte skall användas för "lättviktiga objekt". Det senare kan tom fördröja städningen. Hmm ok, Strängar BTW ... Hej Patrik, Ja det är korrekt. Det är en optimering som GC gör. I och med att ni ropar på Dispose på objektet långt ner i metoden så kommer inte optimeringen att trigga på just det. De behöver inte vara dispose metoden utan kan egentligen vara vilken metod som helst. Hej, Patrik! Japp det är rätt, OK, jag menade inte .NET Remoting explicit, utan "remoting" rent principiellt. Om vi t ex tar en Web Service så får ju dess proxy en Dispose-metod. Är det inte av vikt att anropa denna då från klienten? Beror ju iofs på vad man ska göra, så man inte har enabledsession eller så, men i normalfallet med en stateless WS. Skillnaden är förstås att du inte behöver implementera Dispose/Finalize i ditt serverobjekt, eftersom det är gjort i ramverket. Tack för svaret Patrik. Stänga instanser, object?
Hur är det med instanser och objekt i asp.net. Behöver lite info o ex.
Behöver man ta "död" på instanser till klasser etc? Dataset osv?Sv:Stänga instanser, object?
Sv:Stänga instanser, object?
Sv: Stänga instanser, object?
ett par felaktigheter i era svar tänkte förklara GC lite.
Garbage Collectorn använder sig av en teknik som kallas "reference tracking" för att identifiera de objekt som inte längre behövs. Strax innan den rensar minnet så skapar den en graf över alla sk "reachable objects", dvs objekt som fortfarnade kan accessas ifrån en tråd någonstans.
De objekt som inte hamnar i grafen är de som kommer att kastas. För att ett objekt inte längre skall räknas som "reachable" så kan man sätta variabeln till null (eller nothing i vb) men det är bara ett krav om du vill styra när den blir klar för GC och igentligen bara intressant för klassvariabler.
När det gäller lokala variabler så anses de bara vara "reachable" så länge de är innanför sitt scope (metod, if, for osv).
När det kommer till IDisposible och Dispose metoden så har den ingetning med GC att göra. Det är ett mönster som vi kan implementera i våra klasser för att tillåta de som använder klassen att så tidigt som möjligt rensa globala resurser som klassen använder ( tex om den har en fil öppen under hela sin livstid).
Dispose behövs bara om klassen har referenser till just externa resurser som databas kopplingar, filer osv.
Om man förlitar sig på dispose, dvs man förlitar sig på att de som använder objekt av klassen skall ropa på den, då behöver vi också ett sätt att göra en dispose "automatiskt" om de glömmer det.
Här kommer ngt som kallas Finilizern (destructor) in, om vi definerar en destructor så kommer garbage collectorn att exekvera när objektet är dött. Tyvärr så innebär det också att objektet får vänta till nästa collect för att det skall frigöras, vilket innebär att om jag implementerar en destructor (inte dispose) fördröjer jag hela processen.
Här är ett exempel på hur man implementerar en optimal Dispose/destruktor i C#:
public class Mohead : IDisposible
{
public void Dispose()
{
this.Dispose(true);
}
public void Dispose(bool disposing)
{
// om den som skapat objektet ropar på dipose så vill vi stänga av finilizern
if ( disposing )
GC.SuppressFinilize(this);
// rensa alla EXtERNA(UNMANAgED) resurser,
// .net (MANAGED) behöver vi inte tänka på, det sköter sig självt
}
~Mohead()
{
this.Dispose(false);
}
}
Sv:Stänga instanser, object?
Strängar skall man undvika att klippa ihop (konktanera) eftersom de är ngt som kallas "immutable" - oföränderliga. Det innebär att vill jag göra en förändring på en sträng så kommer .net att skapa en helt ny sträng med det gamla och det nya innehållet och låta variabeln peka på den istället. Det innebär att den gamla strängen oftast inte längre har en variabel som pekar på den och en läggs till historien och väntar på en garbage collect.
Gör vi många sådana här ihopklippningar så kommer det att bli en hel drös med föräldrarlösa strängobjekt på heapen som bara väntar på att bli dödade.
Skall man klippa ihop massvis med sträng data, använd System.Text.StringBuilder. Den är 16 tecken från början, när den går i taket så skapara den en ny som är 32 osv. Det minskar antalet objekt som kommer att skapas (minnesallokering är inte jättebilligt) och minskar antalet objekt som ligger och gör ingenting.
För att vara så optimal som möjligt, skapa en SB med en buffer av ungefär rätt storlek från början. Då minskar vi eller tom eliminerar nya minnesallokeringar och objekt som flyter runt.
StringBuilder sb = new StringBuilder(256);
sb.Append("text");
sb.Append("mer text");Sv:Stänga instanser, object?
Vill gärna ha din kommentar på följande:
Vi använder oss av Dispose inte bara för att städa utan för att fördröja den samma.
void MyMethod()
{
MyObject obj = new MyObject();
MyChildObject child = obj.NewChild();
child.DoSomething();
obj.Dispose();
}
Om vi skulle låta bli att anropa Dispose på slutet så kan obj städas bort innan anropet till DoSomething sker. Förödande för oss eftersom vi har objekt med icke-managerade referenser till varandra.
Vi trodde först inte våra ögon när vi såg detta i våra loggar, men vi hittade vi en artikel av Francesco Balena som bekräftade att om en skräpsamling sker mitt under exekveringen av en metod så kan GC upptäcka att en lokal variabel inte längre används.
Sv: Stänga instanser, object?
Vad är det för "ikke-hanterade" referenser ni har mellan de två objekten? I vissa fall så kommer nämglien ingen städning av ert parent objekt göras i alla fall.
Om child-objektet har en managed referens (objekts variabel på klassnivå tex) så kommer inte parent objektet att städas. Sv:Stänga instanser, object?
Vet inte om jag hade fel i mitt svar, men uttryckte mig inte lika "klockrent" och utförligt som du. Brukar nämligen implementera mina Dispose/Finalizers enligt ditt kodexempel ovan.
En fråga emellertid. Menar du att detta mönster alltid är "waste-of-time" om man inte har några icke-managed referenser? Brukar förespråka detta mönster generellt, åtminstone om det föreligger ett remote-förhållande mellan anropande klient o serverobjekt. Men då är jag ju iofs i första hand struktur-fascist snarare än prestandaoptimerare. Det är ju alltid en avvägning :)
Right or Wriong?Sv: Stänga instanser, object?
det är waste of time om du bara har managed referenser.
När det gäller remoting så är det ju proxyn som är intressant. Då finns det två varianter av proxys, client activated och server activated.
Båda proxyna styr på sitt sätt livstiden på objekten på servern, SA genom att jobba med JITa och CA genom att den dödar referrensen när referensen på klienten dör.
Jag är inte 110 nu, var ngn månad sedan jag kollade på remoting, men där finns ingen "dispose" metod på en CA proxy som släpper objektet på serversidan, vilket gör att genom att endast sätta CA proxyn till null så uppnår du ingen prestanda alls.Sv:Stänga instanser, object?
Samma sak med EnterpriseServices. Som jag ser det är ServicedComponent en "wrapper" för att jag som .NET-utvecklare ska ha tillgång till "icke-managed" COM+ tjänster. ServicedComponent implementerar IDisposable och borde därmed "städas" eftersom den i normalfallet är stateless?Sv:Stänga instanser, object?
Det är C++ objekt som har lite hyss för sig och därför behöver denna specialbehandling. Kodexemplet jag gav var en förenkling. Referensen från child-objektet är icke-hanterad och problemet som uppstod var att man kunde råka anropa detta eftter det att GC plockat bort parent-objektet.
Och visst, vi kunde ha valt vilken metod som helst istället för Dispose för att fördröja städningen, men då det är frågan om poolade COM+ objekt tyckte vi att det verkade vettigt att släppa dem så snart som möjligt...