Mitt program på 2800 rader tar enligt mig enormt mycket minne, mellan 20-25 mb. Jag skulle väldigt gärna villja få ner den siffran lite grann, för så advancerat är programmet inte. Nu kan jag ju inte posta alla 2800 rader utan jag har valt dom delar som jag tror tar mycket minne och som kanske kan förbättras. Men andra tips är också välkommna. Jag optimerade din kod lite. Om din Car[] är enbart till för att fylla en hashtable med data så kan du göra det på följande sätt istället: Bygger du detta för en Win Form? Min timer startas efter att jag kollat att "Market" i mina settings är satt på YES. Jag tar fram mina settings på samma sätt som min Car klass. Den här koden är den första som körs (förutom main, då min frmTrayForm skapas). Testade din optimering, men nu vart programmet 3mb tyngre :/ Hur vet du att programmet använder 20-25mb minne? Menar du enbart data eller både kod + data? Om jag istället för att använda en hashtable för att plocka ut specefik data, skapar en metod i klassen som tar ut datan med en en SQL sats. Det sists fallet fungerar bäst, för i din myCars.GetCars gör du om jag mins rätt en hämtning av data från databas och fyller en hashtable med klasser, vilket tar längre tid än att enbart hämta data och fylla en klass. Det du skulle kunna göra för att få upp prestanda är att utföra ditt första exempel där du fyller en hashtable med klasser och lägger den hashtablen i en variabel som du sedan återanvänder i din applikation. Då har du enbart gjort hämtningen en gång och kan enkelt få ut information om din bil utan att behöva fråga databasen. Om du ska ha möjligheter att kunna uppdatera bilar och sedan uppdatera mot databas, så skulle jag rekommendera dig att använda Dataset istället för att fylla klasser. Ett dataset har ett flertal metoder för att göra utsökning av data, filtrera och sortera data utan prestandakrävnade åtkomst till databas. För att göra det mer enkelt att använda ett dataset så kan du generera en klass som representerar strukturen av datasetet (t ex en user-tabell i ett dataset kan lätt bli åtkomligt som dataset.User). Detta kallas för ett typat dataset. Ett typat dataset gör det lättare, ger en renare kod, och reducerar risken att skapa fel när man utvecklar applikationer med hjälp av ett typat dataset eftersom Visual Studio.Net stödjer verktyg som t ex IntelliSense osv. Ojoj, mycket information på en gång, det är alltid trevligt. Om du enbart ska kunna uppdatera en bil åt gången så tycker jag att du ska ha kvar så som du har nu. Tackar och bockar för alla svar. Sätter tråden som löst nu men har nåpgon något mer tips så är det välkommet. Men jag är nöjd iaf. Tack än en gång. Om jag inte minns fel så kan det här optimeras lite... tvivlar på att det ändrar så mycket men "många bäckar små..."Tips för bättre minneshantering
Jag har flera klasser med följande struktur och jag tror det tar en hel del minne. Detta är inte min grundkod utan väldigt förenklad så ni förstår metoden jag gjort det på.
<code>
class Car
{
public string strModel;
public string strFarg;
public int intAr;
public Hashtable GetCars()
{
Hashtable arrCars = new Hashtable();
Cars[] myCars = new Car[20];
for (int i = 0; i < myCars.GetLength(0); i++)
myCars[i] = new Car();
//Kod för att hämta data från databas och loopa igenom databasen
myCars[counter].strModel = myReader.GetString(1)
myCars[counter].strFarg = myReader.GetString(2)
myCars[counter].intAr = myReader.GetInt32(3)
arrCars.Add(myCars[counter].strModel, myCars[counter]);
counter++;
//Slut kod
}
}
</code>
För att sedan hämta informationen använder jag av ungefär följande kod
<code>
Cars myCars = new Car();
Hashtable htCars = myCars.GetCars();
IDictionaryEnumerator myEnumerator = htCars.GetEnumerator();
while (myEnumerator.MoveNext())
{
MessageBox.Show("Car: "+ myEnumerator.Key +", "+ ((Car)htCars[myEnumerator.Key]).strFarg +", "+ ((Car)htCars[myEnumerator.Key]).intAr);
}
</code>
Min gissing är att denna kod inte är så minnessnål. Jag har 3 olika klasser som alla ser på liknade vis.
Sedan har jag även en Timer som står och går och den tar mycket minne. Finns det något bättre alternativ till timern?
Tips på förbättringar motages gärna.Sv: Tips för bättre minneshantering
<code>
class Car
{
public string strModel;
public string strFarg;
public int intAr;
public Car() {}
public Car( string strModel, string strFarg, int intAr )
{
this.strModel = strModel;
this.strFarg = strFarg;
this.intAr = intAr;
}
public Hashtable GetCars()
{
Hashtable arrCars = new Hashtable();
for( int counter = 0; counter < 20; counter++ )
{
//Kod för att hämta data från databas och loopa igenom databasen
arrCars.Add(myReader.GetString(1), new Car(
myReader.GetString(1),
myReader.GetString(2),
myReader.GetString(3))
);
}
return arrCars;
}
}
</code>
En Window Form tar upp ca: 15 mb i grunden.
Det är inte osannolikt att en Window Form tar runt 20-25 mb. Om du nu vill undvika eller dra ner på att mer minne ska behövas används så kan du tänka på att förebygga detta problem. Det kan du göra på flera sätt och här kommer några som kanske kan vara till hjälpa.
1) Se till att själv sätta dina objekt till null när du är klar med dom.
2) Inför Dispose patten.
3) Använd HybridDictionary istället för en Hashtable. HybridDictionary kan automatiskt gå över till att bli en hashtable om det behövs (Om det förkommer fler än 10 poster). Du använder HybridDictionary på samma sätt som en hashtable. När du har mindre än 10 poster så är Hybrid.. snabbare än en Hashtable på att hämta och data.
Jag skulle rekomendera dig att inte använda hashtable när du ska lista data. Bättre att använda ArrayList för att få ut datan i den ordning som den lagrades. När och varför anävnder du en timer? För att få listan att allitd vara uppdaterad med bilar som kan läggas till av andra?
Mvh Fredrik NorménSv: Tips för bättre minneshantering
I så fall behöver du inte gör på det sättet du gjort, jag hade hämtat den data jag ville ha från databasen då jag behövde den. Finns ingen direkt mening att lägga alla data i x-antal objekt och sedan loopa genom dem för att presentera dem. Istället kör du en presentation direkt från DataReadern. Om du vill hämta en Car post någonstans då kan du fylla ett Car objekt om du vill. Ser din lösning som en liten overkill. Fast jag vet ju inte hur du tänkt att din applikation skall fungeramer än den kod du klistrat in.
//Johan NSv: Tips för bättre minneshantering
<code>
public frmTrayForm()
{
CreateMainCont();
Settings mySettings = new Settings();
Hashtable htSettings = mySettings.GetSettings();
if (((Settings)htSettings["Market"]).strValue == "YES")
{
Market myMarket = new Market();
myMarket.Login();
Timer myTimer = new Timer();
myTimer.Tick += new EventHandler(myMarket.OnTimedEvent);
myTimer.Interval = 13481;
myTimer.Enabled = true;
myTimer.Start();
}
}
</code>
Programmet är ett "Trayprogramm" dvs det ligger i tray och vilar. Sedan kan man genom traymenyn öppna nya formulär.
För att få programmet "osynligt" så hitta jag den här koden på nätet, kanske inte är den bästa varianten
<code>
this.MaximizeBox = false;
this.StartPosition = FormStartPosition.Manual;
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.FormBorderStyle = FormBorderStyle.None;
this.Enabled = false;
this.AccessibleRole = AccessibleRole.None;
this.ShowInTaskbar = false;
this.SizeGripStyle = SizeGripStyle.Hide;
this.ControlBox = false;
this.MinimizeBox = false;
this.ClientSize = new System.Drawing.Size(1, 7);
this.Opacity = 0;
</code>Sv: Tips för bättre minneshantering
Fast koden vart snyggare :)
Testade också att stänga och sätta null på mina databaskopplingar men det vart ingen större skillnad.Sv: Tips för bättre minneshantering
Om du använder taskmanager så ser du enbart hur stor addressrymd som för tillfället är allokerat för din process. Skulle tro att 90% av detta är dll:er som är gemensamma för flera program. Den del som är unik för ditt program är troligen inte särskilt stor och den del som du kan påverka är ännu mindre.
(C# återanvänder i princip inte det minne du frigör genom att sätta objekt till null så minnesanvändingen visar inte hur mycket minne du använder just nu utan hur mycket du använt hittils.)
Tänk på att du måste läsa in en väldans massa rader från databasen för att komma upp i 1 mb data.
Det är rätt att tänka på hur mycket resurser man använder men stirra dig inte blind på minnesanvändningen. Använd de andra råden som gavs i den här tråden när du skriver din kod men bekymra dig inte för vad som visas i taskmanagern.Sv: Tips för bättre minneshantering
<code>
Car myCars = new Car();
Hashtable htCars = myCars.GetCars();
strModel = ((Car)htCars["Volvo"].strModel;
//Byts ut mot
Car myCars = new Car();
myCars = myCars.GetCars("Volvo");
strModel = myCars.strModel;
</code>
Om jag nu har sådana sökningar på 50-75 ställen i koden, vilken är då snabbast?Sv: Tips för bättre minneshantering
Angående att sätta ett objekt till null, det frigör inget minne det som händer är enbart att referensen till heapen försvinner, datan kommer att finnas kvar i minnet och någon gång i framtiden kommer GC ta hand om resning av datan när minnet behövs till andra saker. Genom att sätta ett objekt till null gör också att objektet i GC:n hamnar på en annan nivå och kan firgöras fortare av GC:n när minne behövs.
Du kan implementera Dispose i dina klasser för att själv ta hand om rensning av data etc och speeda upp processen att frigöra minne. Som standard, så kommer GC:n automatiskt att anropa dina objekts finalizer för att återvinna dess minne. Men när du kallar på din Dispose, så är det onödigt för GC att anropa objektes finalizer för du själv har tagit hand om upprensningen av resurser. Om du kör med Dispose så innebär det att minnet objektet använder sig av kommer att fortare kunna återanvändas till andra objekt. Så var Martin Adrian säger om minnesallokeringen så är det helt rätt, och visst kan man strunta att stirra sig blind i att sätt objekt till null för GC tar hand om uppresning av data när så behövs. Men om du vill få upp prestanda på dina applikationer så kan det vara bra att själv göra uppresningen för att reducera den tid och resurser som behövs för GC: att rensa upp dina objekt.
Något som inte fram gick i mitt tidigare inlägg doc, var inte tanken att frigöra minne som är allokeras utan undvika minnesläkor så att applikationen inte ska ta upp mer minne än vad som behövs.
Denna artikel ger en klar bild på hur GC fungerar och hur du kan undvika minnesläckor.
Inspect and Optimize Your Program's Memory Usage with the .NET Profiler API
http://msdn.microsoft.com/msdnmag/issues/03/01/NETProfilerAPI/
/Fredrik NorménSv: Tips för bättre minneshantering
Angående mitt sätt att uppdatera databasen så kör jag på följande vis
<code>
class DB
{
OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"data.mdb\"");
public DB(string strSQL)
{
try
{
OleDbCommand myCommand = new OleDbCommand(strSQL, myConnection);
myCommand.Connection.Open();
myCommand.ExecuteNonQuery();
myConnection.Dispose();
myConnection = null;
}
catch
{
;
}
}
}
</code>Sv: Tips för bättre minneshantering
Tips, gå gärna in på denna site och ta en titt på Microsoft Data Access Application Block.
http://www.gotdotnet.com/Community/Workspaces/Workspace.aspx?id=c20d12b0-af52-402b-9b7c-aaeb21d1f431
Med hjälp av deras blocket kan du minimera din kod vid databas anrop.
/Fredrik NorménSv: Tips för bättre minneshantering
Sv: Tips för bättre minneshantering
Ändra det här:
<code>
MessageBox.Show("Car: "+ myEnumerator.Key +", "+ ((Car)htCars[myEnumerator.Key]).strFarg +", "+ ((Car)htCars[myEnumerator.Key]).intAr);
</code>
Till:
<code>
MessageBox.Show(String.Format("Cars {0}, {1}, {2}", myEnumerator.Key, ((Car)htCars[myEnumerator.Key]).strFarg, ((Car)htCars[myEnumerator.Key]).intAr);
</code>