webForumDet fria alternativet

Minnesanvändning

.NETur .NET

11 svar · 628 visningar · startad av aleborg

Medlem sedan jan. 20013 341 inlägg
Frågan#1

Har ett program som fakturerar kunder.
En gång per månad så faktureras några hundra kunder.

Programmet är skrivet i C# .NET 2.0 och det hämtar alla kunder ifrån databasen.
Kortfattat kan man säga att det görs så här:

//skapar en collection för varje användare
GenericCollection<User> usrColl = new GenericCollection<User>();
//loopar genom alla användare som ska faktureras
User usr = new User();
GenericCollection<ServiceItem> sItem = new GenericCollection<ServiceItem>();
//Loopar in allt som ska faktureras
usr.ServiceItem = sItem;
usrColl.Add(usr);

Det här i sig drar inte speciellt mycket minne, MEN när jag sen loopar igenom min User collection och skapar fakturorna och skriver ut/skickar PDF så börjar minnet ätas upp.

För varje User skapas 2 st bilder, som direkt efter att dom har använts körs Dispose på, även en byte[] som skapas sätts till null. Mitt PrintDocument körs Dispose på, i övrigt skapas inga direkta objekt som bör dra minne eller Dispose kan köras på.

När jag kör programmet och håller koll på det i aktivitetshanteraren så är minnesanvändningen väldigt låg, den ökar vid varje faktura för att sen när fakturan är klar, gå tillbaka till en låg minnes förbrukning. Men trots detta ökar växlingsfilen ganska kraftigt till att efter ett 40-tal fakturor slå i taket och jag får ett out of memory exception.
Jag kan inte i aktivitetshanteraren se vad som förbrukar så mycket minne.

Vad gör man?

Medlem sedan feb. 20002 300 inlägg
#2

aleborg skrev:

Har ett program som fakturerar kunder.
En gång per månad så faktureras några hundra kunder.

Programmet är skrivet i C# .NET 2.0 och det hämtar alla kunder ifrån databasen.
Kortfattat kan man säga att det görs så här:

//skapar en collection för varje användare
GenericCollection<User> usrColl = new GenericCollection<User>();
//loopar genom alla användare som ska faktureras
User usr = new User();
GenericCollection<ServiceItem> sItem = new GenericCollection<ServiceItem>();
//Loopar in allt som ska faktureras
usr.ServiceItem = sItem;
usrColl.Add(usr);

Det här i sig drar inte speciellt mycket minne, MEN när jag sen loopar igenom min User collection och skapar fakturorna och skriver ut/skickar PDF så börjar minnet ätas upp.

För varje User skapas 2 st bilder, som direkt efter att dom har använts körs Dispose på, även en byte[] som skapas sätts till null. Mitt PrintDocument körs Dispose på, i övrigt skapas inga direkta objekt som bör dra minne eller Dispose kan köras på.

När jag kör programmet och håller koll på det i aktivitetshanteraren så är minnesanvändningen väldigt låg, den ökar vid varje faktura för att sen när fakturan är klar, gå tillbaka till en låg minnes förbrukning. Men trots detta ökar växlingsfilen ganska kraftigt till att efter ett 40-tal fakturor slå i taket och jag får ett out of memory exception.
Jag kan inte i aktivitetshanteraren se vad som förbrukar så mycket minne.

Vad gör man?

Svårt att säga varför minnet käkas upp utan någon mer inblick i exakt vad som görs men process Explorer från SysInternals kan ge dig rätt avancerad information om minnesanvändning av t.ex. en .NET-applikation.

Högerklicka på processen som kör faktureringarna och välj Properties. Där har du bl.a. en .NET-tab som kanske kan ge någon hint om vad som kan vara problemet.

Medlem sedan jan. 20013 341 inlägg
#3

Har hittat läckan och det är Printdokument:et.
Men jag lyckas inte förstöra graphics objektet efter varje faktura, har testat:
Graphics g = this.CreateGraphics();
g.Dispose();
men det hjälpte inte, var ska man helst placera disposen för printdocument?

Medlem sedan feb. 20002 300 inlägg
#4

aleborg skrev:

Har hittat läckan och det är Printdokument:et.
Men jag lyckas inte förstöra graphics objektet efter varje faktura, har testat:
Graphics g = this.CreateGraphics();
g.Dispose();
men det hjälpte inte, var ska man helst placera disposen för printdocument?

Helst borde du inte ens köra CreateGraphics().

Använder du PrintPage-eventet på PrintDocument så får du med ett Graphics-objekt i PrintPageEventArgs.

Kolla PrintDocument för ett exempel.

Medlem sedan jan. 20013 341 inlägg
#5

Jag kör normalt inte CreateGraphics, men fick ett tips om att köra det för att direkt köra dispose på det.
Jag kör PagePrint, men där i bör jag väl knappast köra dispose?

Medlem sedan feb. 20002 300 inlägg
#6

aleborg skrev:

Jag kör normalt inte CreateGraphics, men fick ett tips om att köra det för att direkt köra dispose på det.
Jag kör PagePrint, men där i bör jag väl knappast köra dispose?

Inte helt säker på vad du menar men om du plockar Graphicsobjektet från eventargs i PrintPage-eventet och ritar på det precis som vanligt. Om du använder det Graphicsobjektet så finns det ingen anledning till att köra dispose på det.

Sen kör du dispose på ditt PrintDocument när du är klar med utskriften så borde den släppa graphicsobjekt och annat.

Medlem sedan jan. 20013 341 inlägg
#7

Phorpher skrev:

Inte helt säker på vad du menar men om du plockar Graphicsobjektet från eventargs i PrintPage-eventet och ritar på det precis som vanligt. Om du använder det Graphicsobjektet så finns det ingen anledning till att köra dispose på det.

Jag körde det bara för att jag blev rekommenderad det, borttaget nu.

Phorpher skrev:

Sen kör du dispose på ditt PrintDocument när du är klar med utskriften så borde den släppa graphicsobjekt och annat.

Det gör jag men det släpper ändå inte resurserna.

Tänkte mer på om man skulle köra dispose så här:

	private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
	{
		int x = e.MarginBounds.Left;
		int y = e.MarginBounds.Top;

		e.Graphics.DrawImage(img, x, y, e.MarginBounds.Width-45, e.MarginBounds.Height-30);
		e.Graphics.Dispose();
	}

Men det verkar funka, dock kan jag inte testa det i stor skala förren om en månad :e
Jag var rädd för att man skulle förstöra det grafiska objektet innan det kom till skrivaren, vilket skulle resultera i en tom utkrift men så var tydligen inte fallet.
Gjorde en liknande sak fast på Attachment:
Attachment attach = new Attachment( str );
message.Attachments.Add( attach );
attach.Dispose();
Vilket resulterade i att mailet aldrig gick iväg.

Medlem sedan feb. 20002 300 inlägg
#8

Hmm. Ja fungerar det är det ju inget att orda om. Verkar lite märkligt att det suger så mycket resurser dock. Hur stora är bilderna du ritar?

Medlem sedan jan. 20013 341 inlägg
#9

stora...
A4 i 300 dpi

Medlem sedan maj 20012 812 inlägg
#10

Du kan göra hur många Dispose() och sätta hur många objekt till NULL inget av det betyder att den frigör minne :)

Det enda det gör är att berätta för GC att om du behöver använda mer minne så kan du frigöra dessa objekt och så fall minska minnes förbrukningen, men så länge GC inte tycker att du använder för mycket minne så är det inte säkert att den städar upp efter dig, det betyder att du kan köra ditt program i en hel vecka utan att GC har tagit bort en byte data från minnet, eller att den ligger konstant varje sekund och försöker frigöra minne då det behövs bättre någon annanstans.

Du kan forsera GC att köra, men om den städar upp efter dig, är jag inte hundra på, jag har fått köra GC.Collect() två gånger eftervarandar fast jag gjort Dispose() på bilder, för att vara säker på att de verkligen har släppts från minnet. GC.Collect() är dock inget som man bör göra själv, utan det är upp till GC att sköta det, då den faktiskt har bättre koll på när det är bäst tidpunkt att göra en Collect() på.

- M

Medlem sedan feb. 20002 300 inlägg
#11

Gladh skrev:

Du kan göra hur många Dispose() och sätta hur många objekt till NULL inget av det betyder att den frigör minne :)

Det enda det gör är att berätta för GC att om du behöver använda mer minne så kan du frigöra dessa objekt och så fall minska minnes förbrukningen, men så länge GC inte tycker att du använder för mycket minne så är det inte säkert att den städar upp efter dig, det betyder att du kan köra ditt program i en hel vecka utan att GC har tagit bort en byte data från minnet, eller att den ligger konstant varje sekund och försöker frigöra minne då det behövs bättre någon annanstans.

Du kan forsera GC att köra, men om den städar upp efter dig, är jag inte hundra på, jag har fått köra GC.Collect() två gånger eftervarandar fast jag gjort Dispose() på bilder, för att vara säker på att de verkligen har släppts från minnet. GC.Collect() är dock inget som man bör göra själv, utan det är upp till GC att sköta det, då den faktiskt har bättre koll på när det är bäst tidpunkt att göra en Collect() på.

- M

Helt sant. Det man däremot kan fundera på är varför inte GCn när minnet faktiskt börjar bli fullt kör en uppstädningscykel. Windows skickar ett low memory notification när 32MB återstår och GCn ska reagera på den. Dock verkar det fungera si och så med det vad jag har förstått.

Medlem sedan jan. 20013 341 inlägg
#12

Tack för hjälpen!

139 ms totalt · 3 externa anrop · v20260731065814-full.b746b907
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
137 ms — hämta tråd, inlägg och bilagor (db)