Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Speicherproblem
klaus1
myCSharp.de - Member

Avatar #avatar-1666.gif


Dabei seit:
Beiträge: 180
Herkunft: Schörfling a. Attersee

Themenstarter:

Speicherproblem

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
norman_timo
myCSharp.de - Member

Avatar #avatar-1775.jpeg


Dabei seit:
Beiträge: 4.506
Herkunft: Wald-Michelbach (Odw)

beantworten | zitieren | melden

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!”
private Nachricht | Beiträge des Benutzers
klaus1
myCSharp.de - Member

Avatar #avatar-1666.gif


Dabei seit:
Beiträge: 180
Herkunft: Schörfling a. Attersee

Themenstarter:

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 9.992

beantworten | zitieren | melden

Wie startest/Stoppst Du die Threads?

Wäre der ThreadPool nicht besser?
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo klaus1,

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

herbivore
private Nachricht | Beiträge des Benutzers
klaus1
myCSharp.de - Member

Avatar #avatar-1666.gif


Dabei seit:
Beiträge: 180
Herkunft: Schörfling a. Attersee

Themenstarter:

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo klaus1,

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

herbivore
private Nachricht | Beiträge des Benutzers
klaus1
myCSharp.de - Member

Avatar #avatar-1666.gif


Dabei seit:
Beiträge: 180
Herkunft: Schörfling a. Attersee

Themenstarter:

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
klaus1
myCSharp.de - Member

Avatar #avatar-1666.gif


Dabei seit:
Beiträge: 180
Herkunft: Schörfling a. Attersee

Themenstarter:

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
norman_timo
myCSharp.de - Member

Avatar #avatar-1775.jpeg


Dabei seit:
Beiträge: 4.506
Herkunft: Wald-Michelbach (Odw)

beantworten | zitieren | melden

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!”
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 9.992

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
svenson
myCSharp.de - Member



Dabei seit:
Beiträge: 8.746
Herkunft: Berlin

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
DaMoe
myCSharp.de - Member



Dabei seit:
Beiträge: 128

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
klaus1
myCSharp.de - Member

Avatar #avatar-1666.gif


Dabei seit:
Beiträge: 180
Herkunft: Schörfling a. Attersee

Themenstarter:

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
klaus1
myCSharp.de - Member

Avatar #avatar-1666.gif


Dabei seit:
Beiträge: 180
Herkunft: Schörfling a. Attersee

Themenstarter:

beantworten | zitieren | melden

und diese Art von Thread ist weniger Speicherfressend, als wenn ich den Thread beende und wieder starte??
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
klaus1
myCSharp.de - Member

Avatar #avatar-1666.gif


Dabei seit:
Beiträge: 180
Herkunft: Schörfling a. Attersee

Themenstarter:

beantworten | zitieren | melden

erziele ich auch diese effizienz, wenn ich mittels GC.collect() arbeite?
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
tomaten
myCSharp.de - Member

Avatar #avatar-1835.jpg


Dabei seit:
Beiträge: 402
Herkunft: Stolberg (Rhld.)

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo tomaten,

lass uns das offtopic kurz machen (zumal es schon eine Menge Threads zu dem Thema gibt). Wie ich schon sagte:
Zitat
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
private Nachricht | Beiträge des Benutzers
tomaten
myCSharp.de - Member

Avatar #avatar-1835.jpg


Dabei seit:
Beiträge: 402
Herkunft: Stolberg (Rhld.)

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Luke86
myCSharp.de - Member



Dabei seit:
Beiträge: 50
Herkunft: Wien

beantworten | zitieren | melden

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;
private Nachricht | Beiträge des Benutzers
tomaten
myCSharp.de - Member

Avatar #avatar-1835.jpg


Dabei seit:
Beiträge: 402
Herkunft: Stolberg (Rhld.)

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 9.992

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
svenson
myCSharp.de - Member



Dabei seit:
Beiträge: 8.746
Herkunft: Berlin

beantworten | zitieren | melden

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"...
private Nachricht | Beiträge des Benutzers
tomaten
myCSharp.de - Member

Avatar #avatar-1835.jpg


Dabei seit:
Beiträge: 402
Herkunft: Stolberg (Rhld.)

beantworten | zitieren | melden

Zitat
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.
private Nachricht | Beiträge des Benutzers
svenson
myCSharp.de - Member



Dabei seit:
Beiträge: 8.746
Herkunft: Berlin

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
norman_timo
myCSharp.de - Member

Avatar #avatar-1775.jpeg


Dabei seit:
Beiträge: 4.506
Herkunft: Wald-Michelbach (Odw)

beantworten | zitieren | melden

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!”
private Nachricht | Beiträge des Benutzers