Laden...

Speicherproblem

Erstellt von klaus1 vor 18 Jahren Letzter Beitrag vor 17 Jahren 10.527 Views
klaus1 Themenstarter:in
180 Beiträge seit 2005
vor 18 Jahren
Speicherproblem

Hi Leute!

Folgendes Problem:
Habe ein 5000 Zeilen Programm entwickelt mit c# im Visual Studio mit folgendem Problem:
nach einer Weile Messdaten einlesen und Threads starten und Stoppen (Pro Messvorgang einmal nötig), wird die Anwendung so lahm nach 50 Messungen, dass ich nichts mehr machen kann.
Habe im taskmanager entdeckt, dass wenn ich die Oberflächee minimiere, und wieder maximiere, sich der Speicher von bis über 80MB auf 2 reduziert.. Das kann aber auch nicht die Lösung vom Problem sein.
Wie kann ich Speicher freigeben?
dachte dies würde der Garbage Collector ohnehin automatisch machen?

LG, Klaus

4.506 Beiträge seit 2004
vor 18 Jahren

Hallo Klaus!

Das ist ein .NET Phänomen. Es ist in der Tat so, dass beim minimieren viel Speicherplatz freigegeben wird.

Das heißt (leider) nicht, dass er beim Maximieren genauso wenig benötigt, wie im Minimierten Zustand. Ich kann mir nicht vorstellen, dass das erheblich reduzierbar ist.

Aber eine Frage habe ich an Dich:

Wieso musst Du einmal pro Messung einen Thread Starten und Stoppen? Kannst Du das nicht mit einer boolschen Variable steuern. Ich meine, innerhalb Deines Threads um den gesamten Codeblock eine if-Schleife mit Abfrage nach dieser Variablen?

In etwa so:



bool stopThread = false;
bool shouldCollectData = true;

// Thread Anfang
while (stopThread == false)
{

if (shouldCollectData)
{
   // Führe Messung durch
}


Thread.Sleep(10);

}


Ich weiß nicht wie Zeitnah Deine Messungen laufen sollen, eventuell den Sleep auf 1 ms runtersetzen. Das Sleep sorgt zumindest dafür, dass andere Threads an die Reihe kommen.

Beseitigt das Dein Problem?

Ciao
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

klaus1 Themenstarter:in
180 Beiträge seit 2005
vor 18 Jahren

Nein leider nicht!
Um den Thread komm ich nicht herum!
Ich steuere Hardware an, und muss während dem Einlesen einer Spannung auf einem Digitalen Ausgang pulse schicken.. und nach beenden der Messung auch den Thread mit dem Digial Ausgang wieder stoppen.
daran ist nichts zu ändern.
Nur nach 50messungen ist es vorbei mit dem Programm.
Man muss doch selber auch noch irgendwie Speicher freigeben können?
bitte um Hilfe!
LG, Klaus

F
10.010 Beiträge seit 2004
vor 18 Jahren

Wie startest/Stoppst Du die Threads?

Wäre der ThreadPool nicht besser?

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo klaus1,

ich denke nicht, dass jeweils ein neuer Thread nötig ist. Und scheinbar ist es ja kontraproduktiv, so viele zu starten.

herbivore

klaus1 Themenstarter:in
180 Beiträge seit 2005
vor 18 Jahren

naja, starten und stoppen über verlassen der schleife... mehr nicht.. wird mir dann angezeigt: Thread wurde beeendet..
Doch nicht ganz beendet, bzw. aus dem Speicher??

Wie kann ich ansonsten das Problem lösen? muss gleichzeitig Spannungen einlesen auf einer NI Messkarte...
LG, Klaus

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo klaus1,

ich denke es müsste reichen, einen Thread zu erzeugen, der dann in einer Schleife die Spannungen einliest.

herbivore

klaus1 Themenstarter:in
180 Beiträge seit 2005
vor 18 Jahren

Tja, das Prolem ist folgendes:

Es geht hier um eine zeitkritische Messung, die alle 15msec. Werte einliest (Kraftsensoren), und postition von Motoren.
Diese Werte müssen in einem vordefinierten Timer Zeit Intervall geliefert werden. Nebensächlich wird ein Thread gestartet mit niedriger Priorität, der dafür zuständig ist, dass über 3 digitale Ausgänge eine digitale Anzeige angesteuert wird.
Beim Stoppen der Messung, wir der Thread für die Anzeige beendet, und der Hauptthread weiter alleine ausgeführt!
Es ist hier unbedingt ein weiterer Thread notwendig!
LG, Klaus

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo klaus1,

auf einem Single-CPU-Rechner wird ein Programm durch (viel) mehr Threads nicht schneller, sondern langsamer (das bekommt du ja gerade zu spüren). Wenn deine Messung zeitkritisch ist, solltest du so wenig wie möglich Thread benutzen. Natürlich braucht man in der Regel eine Trennung von GUI und Verarbeitung. Vielleicht ist hier auch eine Trennung von GUI, Messung (einlesen) und Verarbeitung nötig. Das sollte es dann aber auch gewesen sein.

herbivore

klaus1 Themenstarter:in
180 Beiträge seit 2005
vor 18 Jahren

ich habe bereits trennung zwischen gui messung und verarbeitung.. jeweils in eigenen threads, da ich die daten während der messung schon verarbeiten muss, und grafisch per GRAPH anzeigen lassen muss!
Lg, Klaus

4.506 Beiträge seit 2004
vor 18 Jahren

Hallo Klaus!

Wenn Du meinen Vorschlag oben anwenden würdest, dann hättest Du die Möglichkeit, einmal den Thread am Leben zu lassen mit Hilfe der "stopThread" Variablen.

Mit Hilfe der "shouldCollectData" Variable hast Du die Möglichkeit eine "sinnvolle" Arbeit für den lebenden Thread zu steuern. Also "shouldCollectData = true", er geht in die Verarbeitung (if-Bedingung), und "shouldCollectData = false", er macht nix, außer dass er sich wieder für eine Millisekunde schlafen legt.

Das kannst Du mit allen 3 Threads machen für GUI, Verarbeitung und Einlesen. Und zwar ohne, dass Du wirklich einen Thread echt stoppen müsstest. Also rein über die Bool-Variable. Sinnvoll wäre es nur, und das kannst Du durch Ausprobieren herausfinden, eine angebrachte Zeit einzustellen, für wie lange der Thread sich schlafen legt.

Funktioniert das bei Dir nicht?

Ciao
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

F
10.010 Beiträge seit 2004
vor 18 Jahren

Meine Frage zielte darauf, ob du wirklich die Threads dann auch beendest,
und disposed, oder ob sie weiter in dem Prozess Zeit ziehen.

Schau Dir dazu mal diesen Artikel/diese komponente an:
http://www.codeproject.com/csharp/SmartThreadPool.asp

S
8.746 Beiträge seit 2005
vor 18 Jahren

Nix für Ungut, aber wenn ich höre "50 msec", dann denke ich, dass du entweder ein Real-Time-OS nehmen solltest, oder einfach den gesamte Steuerung an eine echtzeit-fähig Hardware auslagern solltest. NI bietet solche Karten mit eigenem Prozessor und BS an. Mit Windows solltest du nur das GUI machen.

D
128 Beiträge seit 2005
vor 18 Jahren

Hallo zusammen!

Mal von den ganzen anderen Loesungsvorschlaegen abgesehen, kannst Du den Garbage Collector auch von Hand anweisen, dass er taetig wird.

GC.Collect()

sollte es eigentlich tun. Ob das nun so sauber ist, ist halt die Frage. Vielleicht hilft es ja.

Greetz, DaMoe

klaus1 Themenstarter:in
180 Beiträge seit 2005
vor 18 Jahren

wird GC.Collect() nach dem Beenden eines Threads aufgerufen, oder wo genau?

Threads starten, dazu erzeuge ich neue Threads, da ich angehaltene Threads kein zweites mal starten kann!
Dies ist deshalb nicht möglich, weil ich sobald ich die Schleife verlasse, der Thread laut DOTNet Debugger beendet wird.
LG, Klaus

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo klaus1,

GC.Collect() kannst du aufrufen, wo immer du meinst, der GC sollte mal was tun.

Natürlich kann man einen beendeten Thread nicht weiter verwenden. Aber du kannst den Thread ja einfach am laufen halten. Zum Beispiel kann der Thread, der die Arbeit verrichten soll, eine Queue verwenden. Er guckt nach, ob was in der Queue ist, wenn ja arbeitet er. Wenn nichts in der Queue ist, wartet er auf eine Semaphore. Jemand der Arbeit für den Thread hat, packt die Arbeit in die Queue und signalisiert der Semaphore. Dadurch wacht der Thread auf, holt sich die Arbeit aus der Queue und so geht es wieder von vorne los.

herbivore

klaus1 Themenstarter:in
180 Beiträge seit 2005
vor 18 Jahren

und diese Art von Thread ist weniger Speicherfressend, als wenn ich den Thread beende und wieder starte??

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo klaus,

auf jeden Fall, vor allem aber weniger Laufzeit fressend. Und wenn der Thread sowieso weiß, was er zu tun hat (nur nicht wann), geht es sogar ohne Queue und nur mit Semaphore (AutoResetEvent oder Mutex).

herbivore

klaus1 Themenstarter:in
180 Beiträge seit 2005
vor 18 Jahren

erziele ich auch diese effizienz, wenn ich mittels GC.collect() arbeite?

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo klaus1,

ich denke nicht, der CG braucht ja im Gegenteil erstmal zusätzliche Zeit. Die Erzeugung eines Threads ist im Vergleich zum Signalisieren einer Semaphore auf jeden Fall deutlich teuerer.

herbivore

402 Beiträge seit 2005
vor 18 Jahren

Möchte mal kurz vom Thema abweichen, denn der GC.collect interessiert mich. Habe ja eine ASP.NET Anwendung die mir nach einem Tag 400MB in den Speicher knallt. Gibt es da einen sinnvollen Punkt, wo man den GC.collect nutzen kann?

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo tomaten,

lass uns das offtopic kurz machen (zumal es schon eine Menge Threads zu dem Thema gibt). Wie ich schon sagte:

GC.Collect() kannst du aufrufen, wo immer du meinst, der GC sollte mal was tun.

Sinnvollerweise natürlich nachdem du viele Variablen auf null gesetzt hast. Der GC gibt ja nur Objekte frei, die (per Referenz) nicht mehr erreichtbar sind.

herbivore

402 Beiträge seit 2005
vor 18 Jahren

Das dürfte in eine ASP.NET Anwendung eine Menge sein, da die meistens nur in irgendwelche Events verwendet werden. Aber nach jedem Request GC.collect zu machen, dürfte die Sache nicht unbedingt beschleunigen!?

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

L
50 Beiträge seit 2005
vor 18 Jahren

Also ich gebe die nicht benötigten ressourcen für mein Programm so frei:

[DllImport("kernel32")]
private static extern int SetProcessWorkingSetSize (int hProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize);

SetProcessWorkingSetSize((int)System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);

bin mir nichtmehr sicher ob diese Konstanten zu diesem Aufruf dazu gehören 😭

	public const int HTCAPTION = 2;  
	public const int WM_NCLBUTTONDOWN = 0xA1;  
	public const int WM_SYSCOMMAND = 0x112;
402 Beiträge seit 2005
vor 18 Jahren

Das Konstrukt sieht aber merkwürdig aus, zumal Du Win32 Funktionen nutzt um .NET Speicher freizugeben?

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

F
10.010 Beiträge seit 2004
vor 18 Jahren

Diese Funktion sagt dem BS das dieser Prozess einen "auf den Deckel" bekommt,
wegen Speicherverschwendung.

Dann sagt Windows dem FW bescheid, das wiederum den GC anschmeisst.

Ist aber wirklich der Falsche weg.

Den GC selber aufzurufen bringt im allgemeinen mehr Probleme als ohne.

Auch wenn alle behaupten das .NET alles selbständig freigibt, stimmt das nicht.
Alle Klassen, die eine expliziete Speicherfreigabe benötigen, haben Dispose()
implementiert, und das muss auch aufgerufen werden.
Das vergessen die meisten Leute.
Wozu gibt es schliesslich "using"?

Dann statt einzelner Streads lieber den ThreadPool verwenden.

Dann mal darüber nachdenken ob Echtzeit wirklich in eine .NET Anwendung gehört.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Mich würden mal genaue Informationen interessieren, wann genau der GC eigentlich von allein anspringt. Im Netz ist kaum was zu finden, außer Aussagen wie "selbstoptimierend"...

402 Beiträge seit 2005
vor 18 Jahren

Original von FZelle
Alle Klassen, die eine expliziete Speicherfreigabe benötigen, haben Dispose()

Da habe ich wohl bisher .NET gründlich falsch verstanden? Woran erkenn ich die?

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Dispose() gibt keinen .NET-Speicher frei, sondern Win32-Ressourcen. Also Handles, unmanaged Speicher, etc.! Das ganze ist eine reine Konvention. Das Schliessen eines Streams z.B. führt bereits bei Close() zur File-Handle-Freigabe.

Zu erkennen an IDisposable-Implementierung.

4.506 Beiträge seit 2004
vor 18 Jahren

Hallo Tomaten!

Ich glaube nicht, dass Du das grundsätlich falsch verstanden hast. Aber um auf Deine Frage zu antworten:

Dispose ist eine Methode, die unbedingt implementiert werden muss, sobald die Schnittstelle IDisposable angewendet wird.

Du findest dies z.B. standardmäßig bei WinForm-Applikationen.

Einfach nur schauen, ob es die Methode gibt, dann weißt Du, ob Du Dich selbst drum kümmern musst, oder nicht.

Ciao
Norman-Timo

[EDIT] Zu langsam 😉 [/EDIT]

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

402 Beiträge seit 2005
vor 18 Jahren

Zum Verständniss:

Wenn ich eine Klasse habe, die Klassen die IDisposable implementiert haben verwenden, sollte die Klasse auch IDisposable implementieren um diese entsprechend freizugeben? Also so wie immer unter Win32, nur hier eben bedingt?

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Generell ja, im Einzelfall kann man es sich u.U. schenken. Wenn die Ressourcen-Menge pro Objekt klein ist und die Zahl der Objekte selbst beschränkt, kannst du die Aufgabe dem GC überlassen. Letztlich ist es natürlich sauberer IDisposable zu implemntieren. Es bleibt ja noch dem User überlassen, Dispose() aufzurufen oder nicht.

402 Beiträge seit 2005
vor 18 Jahren

Ah, ich verwende sehr oft IDbCommand und das hat IDisposable. Da muss ich mal was tun! 😉 Da brauch ich mich nicht zu wundern. Ah, wie bemerkt bin ich noch temporärer C# Gast. Wie ist der korrekte Syntax für einen Destructor. Habe da auch schon wieder mehrere Versionen gesehen 🙁 !

Also 1:

protected override void Dispose ...

oder 2:

~MyClass()

Welches ist nu richtig? 🙁

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo tomaten,

beides ist richtig. Das erste ist eine Dispose-Methode und das zweite ist der Destruktor.

Wenn ich eine Klasse habe, die Klassen die IDisposable implementiert haben verwenden, sollte die Klasse auch IDisposable implementieren um diese entsprechend freizugeben?

Nein, nicht grundsätzlich, es muss nur sichergestellt werden, dass für die Objekte, die ein Dispose haben, dieses aufgerufen wird, sobald die Objekte nicht mehr gebraucht werden. Um das sicherzustellen, ist nicht immer notwendig IDisposable zu implementieren. Es kommt darauf an, wie du die enthaltenden Objekte benutzt.

herbivore

402 Beiträge seit 2005
vor 18 Jahren

Z.B. hab ich ein IDbCommand in einer Klasse in Benutzung, dass so lange existiert wie die Klasse. In diesem Fall wäre das doch angebracht, damit ich beim Dispose der Klasse ein IDbCommand.Dispose machen kann!? IDbCommand wird im Constructor der Klasse erzeugt. Oder reicht es, dass ich den IDbCommand.Dispose im Destructor der Klasse mache? Dann bin ich ja wieder etwas vom GC abhängig.

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo tomaten,

ja, in diesem Fall (und in ähnlichen Fällen) wäre das sinnvoll.

herbivore

402 Beiträge seit 2005
vor 18 Jahren

Habe o.a. noch was angefügt. Sorry, evtl. gibts noch ne Anmerkung dazu?

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo tomaten,

der Destruktor sollte Dispose aufrufen, aber Dispose sollte auch durch den Benutzer aufrufbar bleiben. Wie du richtig geschrieben hast, bist du sonst dem CG ausgeliefert.

herbivore

402 Beiträge seit 2005
vor 18 Jahren

Original von herbivore
Hallo tomaten,

der Destruktor sollte Dispose aufrufen, aber Dispose sollte auch durch den Benutzer aufrufbar bleiben. Wie du richtig geschrieben hast, bist du sonst dem CG ausgeliefert.

herbivore

Aber ich kann doch nicht IDbCommand.Dispose nicht im Dipose und im Constructor aufrufen? Das geht doch nur einmal, oder? 🤔

Gott ne und wer noch mehr verwirrt werden will, der lese hier:

MSDN Dispose

Da war es doch schöner, als man unter Win32 jede Klasse erzeugt und wieder freigegeben hat. Man hat einfach mit (Delphi) Create gleich den Free drunter gesetzt und dazwischen seinen Code und alles war in Ordnung!

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

F
10.010 Beiträge seit 2004
vor 18 Jahren

Es ist wie immer etwas komplizierter.

Es gibt in C# zwar Destruktoren, aber die müssen nicht unbedingt aufgerufen werden.
Was sich MS dabei gedacht hat weis keiner, ist aber so.

Wenn Du also Unmanaged Resourcen benutzt,
musst Du sie im Dispose aufrufen, aber nur, wenn der Destruktor vorher
nicht schon zugeschlagen hat.
Alles klar? 😉)

Es gibt das sog. Disposable-Pattern,
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconFinalizeDispose.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/dotnetgcbasics.asp

402 Beiträge seit 2005
vor 18 Jahren

Das u.a. Zitat ( (c) Microsoft 😉 ) erklärt zumindest für's erste meinen Fall.:

When implementing this method, objects must seek to ensure that all held resources are freed by propagating the call through the containment hierarchy. For example, if an object A allocates an object B, and object B allocates an object C, then A's Dispose implementation must call Dispose on B, which must in turn call Dispose on C. Objects must also call the Dispose method of their base class if the base class implements IDisposable.

Wobei das Beispiel darunter mein ganzen Resourcen zu dem Thema für heute "Disposed" 😉 !

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo tomaten,

vielleicht klärt die Implementierung, die ich in meinen Klassen verwende, einiges:


//#######################################################################
// Close, IDisposable.Dispose, Dispose (bool) und Destruktor (= Finalize)
//
// Die eigentliche Logik findet in Dispose (bool) statt. Deshalb ist
// Dispose (bool) auch virtual. Unterklassen können hier die
// Funktionalität der Objektzerstörung erweitern.
//
// Alle anderen Methoden rufen nur direkt oder indirekt Dispose (bool)
// auf. Deshalb sind sie absichtlich nicht virtual.
//
// - Close ist für die Verwendung durch den Benutzer der Klasse gedacht.
//
// - IDisposable.Dispose dagegen die Implementierung von der IDisposable
//   Schnittstelle gedacht und wird z.B. bei Verwendung der
//   using-Anweisung aufgerufen.
//   (Man sieht, dass in diesem Fall Close umgangen wird, aber deshalb
//   ist Close ja auch nicht virtual.)
//
// - Der Destruktor ist für den Aufruf durch den GC gedacht.
//
// Durch den Parameter von Dispose (bool) kann man unterscheiden, ob
// Dispose (bool) vom Benutzer oder vom CG aufgerufen wurde. Da beim
// Aufruf durch den CG die enthalteten Objekte schon garbage-collected
// sein können, darf man auf diese nicht mehr zugreifen.
//
// Optional: Wenn die Bezeichnung 'Close' für das Beenden der Lebensdauer
// von Objekten einer Klasse unzutreffend oder irreführend wäre, kann
// man auch den Namen 'Close' durch 'Dispose' ersetzen, ohne die
// Implementierung zu ändern. Die andere Option für diesen Fall wäre,
// die Close-Methode zu entfernen und 'IDisposable.Dispose' in 'Dispose'
// umzubenennen.
//
//#######################################################################

//=======================================================================
public void Close ()
{
   ((IDisposable)this).Dispose ();
}

//=======================================================================
void IDisposable.Dispose ()
{
   Dispose (true);
   GC.SuppressFinalize (this);
}

//=======================================================================
~MyClass ()
{
   Dispose (false);
}

//=======================================================================
protected virtual void Dispose (bool fDisposing)
{
   if (fDisposing) {
      // Hier die verwalteten Ressourcen freigeben
   }
   // Hier die unverwalteten Ressourcen freigeben
}

herbivore

402 Beiträge seit 2005
vor 18 Jahren

Ja das räumt das M$ Beispiel etwas auf. Dann will ich mal implementieren. 🙁

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

402 Beiträge seit 2005
vor 18 Jahren

Jetzt wird es spannend. Meine Klasse basierte auf einer Klasse die das IDisposible schon implementiert hat. Na langem suchen für diesen Fall, war es doch ganz einfach 🙂 .

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

402 Beiträge seit 2005
vor 18 Jahren

@herbivore und an alle anderen

Danke, jetzt läuft meine "havy traffic" ASP.NET Anwendung ohne in der Stunde 100MB RAM zusätzlich zu verbraten. Jetzt sieht es fast wieder wie bei Win32 aus!
Es geht jetzt immer +/- 30 MB rauf und brav irgendwann wieder runter. Deshalb nur fast wie Win32. Da wurden aber die Objekte auch sofort wieder freigegeben. Aber das wissen ja alle hier.

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

S
285 Beiträge seit 2005
vor 17 Jahren

Bin mal in diesem Thread gelandet.

Meine Applikation wächst ständig. Jede 30-40 Sek. etwa 4kb-20kb.

@herbivore
Du hast trotzdem einen Bug im Code. Ich bin da nicht der Profi, aber der GC kann dir einen Strich durch die Rechnung machen, wenn das Objekt vor dem Dispose Aufruf zerstört ist (und Dispose noch ausgeführt werden kann, paradox aber es geht) . Hatte einen ähnlichen Code, werde kurzfristig nachschauen und dann posten.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Sera,

Du hast trotzdem einen Bug im Code.

bis zum Beweis behaupte ich das Gegenteil.

Ich gehe natürlich davon aus, dass der Code zum Freigeben der (verwalteten und unverwalteten) Ressourcen so realisiert ist, dass er ohne Schaden mehrfach aufgerufen werden kann.

herbivore

S
285 Beiträge seit 2005
vor 17 Jahren

Eine andere Frage herbivore,

Wenn du in der virtual verwaltete Ressourcen freigibst, welche sind das dann? z.B in einer Schleife erstelltes Objekt lässt sich schwer freigeben( oder sollte die Deklaration am besten auch lokal deklariert werden um nicht immer ein neues Objekt erstellen zu müssen?)

Habe übrigens auch das Speicherverhalten meiner Applikation getestet. Es bleibt nichts im Speicher, jedoch wird trotzdem meine Apllikation größer und frißt Speicher.

Form.ShowDialog() ... Speicher belastet, ist ja klar
Form.Close() ..... wird nicht weniger
Erneutes Laden der Form .... Speicherauslastung erhöht sich diesmal nicht. Komisch, oder? Passt eigentlich, aber Speicher könnte ruhig freigegeben werden.

Kann es sein, daß jede Form als Referenzkopie im Speicher bleibt?

Arbeitest du mit "beliebiges Objekt = null", bringt das was, da der Verweis auf das Objekt gelöscht wird und der GC dies finden müsste?

Was den Bug betrifft, habe ich das Dispose(false) übersehen. Also war es mein Fehler.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Sera,

Eine andere Frage

hehe, dass sind aber deutlich mehr Fragen als eine. 🙂

Wenn du in der virtual verwaltete Ressourcen freigibst, welche sind das dann?

Die Objekte, die von Feldern (Instanzvariablen) referenziert werden, und IDisposable implementieren.

z.B in einer Schleife erstelltes Objekt lässt sich schwer freigeben

Warum? Geht doch problemlos. Natürlich nicht in Dispose, sondern in der Schleife selbst. Für ein Objekt, das IDisposable implementiert, sollte so früh wie möglich Dispose aufgerufen werden. Für solche Objekte, die nur lokal benötigt werden, bietet sich die Verwendung using () {} an.

(oder sollte die Deklaration am besten auch lokal deklariert werden um nicht immer ein neues Objekt erstellen zu müssen?)

Ob man ein neues Objekt erstellen muss oder nicht und wielange das Objekt lebt/leben soll, bestimmt wo die Variable deklariert werden muss/solle; nicht anderesherum.

Habe übrigens auch das Speicherverhalten meiner Applikation getestet. Es bleibt nichts im Speicher, jedoch wird trotzdem meine Apllikation größer und frißt Speicher.

Wenn du den Speicherverbrauch mit dem Taskmanager misst, ist das nur die halbe Wahrheit.

Kann es sein, daß jede Form als Referenzkopie im Speicher bleibt?

Dispose gibt das Objekt selbst ja nicht frei. Deshalb bleibt das Form-Objekt solange im Speicher, bis der GC zuschlägt.

Arbeitest du mit "beliebiges Objekt = null",

Selten und wenn dann nicht wegen des GCs.

bringt das was,

Ich kann mir Fälle vorstellen, aber normalerweise nicht.

da der Verweis auf das Objekt gelöscht wird und der GC dies finden müsste?

Sicher gibt es Fälle, in denen die Speicherfreigabe dadurch beschleunigt wird. Aber das alleine rechtfertigt in den meisten Fällen die zusätzliche Anweisung nicht. Es ist ja gerade ein Vorzug, sich um die Speicherverwaltung so wenig wie möglich kümmern zu müssen.

herbivore

S
285 Beiträge seit 2005
vor 17 Jahren

Danke für die Antwort"en" 😁

Nun, der Taskmanager muß trotzdem nach längerem Scan der App auch Werte anzeigen, die unter dem höchsten Speicherverbrauch stehen. Bei mir ist immer aktueller = höchster.

Gibt es eine Alternative zum Taski?

"using" muss ich mal testen.