Gå til innhold

C#: Minnelekkasje? Noe jeg kan gjøre for å forhindre det?


Anbefalte innlegg

Hei

 

Har ett program som overvåker stadardskriver på PC-en og i visse tilfeller skal ny standardskriver settes.

 

dette gjør jeg slik:

 

public static bool setDefaultPrinter(string printerName)

{

try

{

System.Diagnostics.Process proc = new System.Diagnostics.Process();

proc.EnableRaisingEvents = false;

proc.StartInfo.FileName = "rundll32.exe";

proc.StartInfo.Arguments = "printui.dll,PrintUIEntry /y /n \"" + printerName + "\"";

proc.Start();

proc.Close();

return true;

}

catch (Exception ee)

{

return false;

}

}

 

Det jeg ser i taskmanager er at hver gang denne kjøres ser det ut til at programmet bruker mer minne. Hvorfor?

 

Er det noe jeg kan gjøre for å forhindre dette? Er ganske viktig at programmet ikke bruker for mye minne.

Endret av JV
Lenke til kommentar
Videoannonse
Annonse

Takk takk. Får prøve den. :yes:

 

Forstår at "alt" står i DOKUMENTASJONEN men ikke alle har tid til å lese hele DOKUMENTASJONEN da jeg vil tro denne er rather stor. Bruker den når jeg vet hva jeg skal se etter, men hadde jeg visst om .Dispose() ville jeg sikkert også kunne lese om den.

Lenke til kommentar

Bruk using isteden:

 

 

using(System.Diagnostics.Process proc = new System.Diagnostics.Process())
{
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = "rundll32.exe";
proc.StartInfo.Arguments = "printui.dll,PrintUIEntry /y /n \"" + printerName + "\"";
proc.Start();
proc.Close();
}

 

Da blir proc GARANTERT disposet uten at du strenger .dispose, try/catch og if-setninger, etc...

 

Btw: .Net gir ikke nødvendigvis fra seg minnet med en gang. Jeg tror ikke du har en minnelekasje, men rett og slett at garbage collectoren ikke har frigitt minnet ennå. Hvis dette er et problem for deg kan du prøve å kjøre GC.Collect();

Lenke til kommentar
Forstår at "alt" står i DOKUMENTASJONEN men ikke alle har tid til å lese hele DOKUMENTASJONEN da jeg vil tro denne er rather stor. Bruker den når jeg vet hva jeg skal se etter, men hadde jeg visst om .Dispose() ville jeg sikkert også kunne lese om den.

 

Jeg har heller ikke sagt at du skal lese hele, men kanskje de delene som omhandler det objektet du har spørsmål om? Siden du også "vil tro" at dokumentasjonen er ganske stor, så har du tydeligvis ikke prøvd en gang.

Lenke til kommentar
De sterke disposer manuelt.

 

Etter det jeg har forstått, så gjør disposing noe slikt:

 

(obj as IDisposing).Dispose();

 

Så det spiller ingen rolle, men med using er det enklere å huske.

 

Ja, men using() sørger også for at man slipper try/finally, if (for å sjekke om objekter er null ), etc... Den blir automatisk disposet når objektet går ut av scope....

 

 

EnDisposableKlasse obj;
try
{
 obj = new EnDisposableKlasse();
 obj.Noe(); // kræsjer?
}
catch
{
  throw;
}
finally
{
 if( obj != null )
 obj.Dispose();
}

 

vs.

 

using(EnDisposableKlasse obj = new EnDisposableKlasse())
{
obj.Noe();
}

 

 

Forskjellen er 4 linjer kode istendefor 15 :)

Endret av jorn79
Lenke til kommentar
using(EnDisposableKlasse obj = new EnDisposableKlasse())
{
obj.Noe(); 
}

Og hva med feilhåndtering hvis obj.Noe() kaster en exception?

 

Det er hele poenget! Da forsvinner den ut av using() scope't, og blir automagisk disposet! :new_woot:

 

Funksjonaliteten i de to kodesnuttene er helt lik. Og som du ser så er det mye enklere å lage kode som oppfører seg *riktig* vha using().

Endret av jorn79
Lenke til kommentar

Bare for å ha ting på det rene. Om en objekt ikke implementerer iDisposable, vil da fortsatt USING sørge for å dispose objektet riktig? Eller bruker Usin iDisoable interfacet implisit?

 

Eks. Hva skjer her?

class EnKlasse
{
int enInt;
}
using(EnKlasse k = new EnKlasse())
{
 k.enInt = 10;
}

Vil k være disposet skikkelig nå? Eller må jeg implementere iDisposable for at dette faktisk skal virke?

 

En annen ting. Hva med objekter som er definert i en klasse utefor metoder? Man kan vel ikke bruke USING utenfor CODE scope?

Altså, hvordan ville man skrevet denne klassen med USING bruk?

class  MinKlasse
{
EnAnnenKlasse k = new EnAnnenKlasse();
public void SettIVerdi()
{
	k.i = 10;
}
public void VisIVerdi()
{
	Console.WriteLine(k.i.ToString());
}
}
class EnAnnenKlasse
{
int i;
}

antagligvis er 90% av min kode laget på denne måten. Hvordan skal jeg da kunne bruke USING?

Lenke til kommentar
using(EnDisposableKlasse obj = new EnDisposableKlasse())
{
obj.Noe(); 
}

Og hva med feilhåndtering hvis obj.Noe() kaster en exception?

Det er jo nettopp det at obj.Noe() kan kaste en exception som er grunnen til at man bruker using :) Som nevnt tidligere i tråden, using er bare en finere måte å si try-finally plusspluss.

Lenke til kommentar
Bare for å ha ting på det rene. Om en objekt ikke implementerer iDisposable, vil da fortsatt USING sørge for å dispose objektet riktig? Eller bruker Usin iDisoable interfacet implisit?

 

Eks. Hva skjer her?

class EnKlasse
{
int enInt;
}
using(EnKlasse k = new EnKlasse())
{
 k.enInt = 10;
}

Vil k være disposet skikkelig nå? Eller må jeg implementere iDisposable for at dette faktisk skal virke?

 

En annen ting. Hva med objekter som er definert i en klasse utefor metoder? Man kan vel ikke bruke USING utenfor CODE scope?

Altså, hvordan ville man skrevet denne klassen med USING bruk?

class  MinKlasse
{
EnAnnenKlasse k = new EnAnnenKlasse();
public void SettIVerdi()
{
	k.i = 10;
}
public void VisIVerdi()
{
	Console.WriteLine(k.i.ToString());
}
}
class EnAnnenKlasse
{
int i;
}

antagligvis er 90% av min kode laget på denne måten. Hvordan skal jeg da kunne bruke USING?

 

Du kan ikke bruke using() på klasser som ikke implementerer IDisposable.

 

Hvis du bruker klasser som kan "lekke ressurser" på den måten du har vist, så bør DIN klasse implementere IDisposable, og være nøye på å .Dispose() objektene du har laget i din sin klasse din .Dispose(). Og når du bruker klassen din bør du bruke using på den. I eksempelet ditt bruker du kun int klassen, og i dette tilfellet er det ikke nødvendig å tenke på dette.

 

class  MinKlasse : IDisposable
{
// .. kode her...

 public void Dispose()
 {
 // Sjekke at EnAnnenKlasse != null, og dispose, etc...
 }
}

 

"Lekke ressurser" betyr: Siden objektene du bruker sansynligvis implementerer IDisposable så vil ressursene kun lekke til GC kjører. Men for endel ressurser som IO(filer), databaseconnections, GDI, etc så bør disse frigis så fort som mulig.

 

 

----

 

Eksmpel:

Jeg har laget en egen Query klasse som tar for seg databasespørringer. Når denne klassen blir brukt vil connection og datareader objekter være åpne mens klassen "kjører". Derfor har jeg latt denne klasssen implementere IDisposable, og i .Dispose() passer jeg på å lukke alle connection og datareader objekter som har blitt laget. Dette fordi jeg ikke kan bruke using() på connection og datareader objektene som blir værende åpne "lengre enn 1 funksjon"...

 

using( Query q = new Query() )
{
  q.AddParameter("@Test", 5);
  q.Execute("spTest");
  while( q.Read() )
 Console.WriteLine( q["Test"] );
}

Endret av jorn79
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...