Also folgendes:
Ich habe eine Klasse die Audio daten wiedergibt. Und jetzt habe ich gerade eine kleine Test-App geschrieben für die ersten mp3 tests. Und bis dahin hat es auch nie solche Probleme gegeben. Doch wenn ich jetzt die ganze Zeit die Größe des Fensters verändere wird aufeinmal die Klasse zerstört. Ich habe keine Ahnung wieso. Kann man nicht in der Klasse etwas mache, dass der GC. überhaupt nicht mehr das Teil zerstören darf? Oder zumindest solange nicht bis ich Dispose manuell aufrufe.
Hier der Coder der Testapp welcher an sich nix großes ist und aber funktioniert solange ich nich am Fenster rumziehe....
namespace Mp3FrameConverterTest
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog ofn = new OpenFileDialog();
ofn.ShowDialog();
Mp3File file = new Mp3File(ofn.FileName);
WaveOut waveOut = new WaveOut(file);
waveOut.Init();
waveOut.Play();
}
}
}
Hi thefiloe,
wie kommst du darauf, daß der GC dir Objekte zerstört? Hast du da irgendwelche Anhaltspunkte dafür, und wenn ja, warum enthältst du die uns vor?
Christian
Weeks of programming can save you hours of planning
Hallo thefiloe,
der GC räumt ein Objekt ab, wenn keine Referenz merh darauf besteht. In deinem Code sind Mp3File und WaveOut innerhalb einer Methode deklariert, d.h. nach verlassen der Methode kann der GC diese abräumen. Mach Felder daraus, dann wird die Referenz auch nach dem verlassen der Methode gehalten und der GC räumt es nicht mehr ab.
public partial class frmMain : Form
{
private Mp3File _mp3File;
private WaveOut _waveOut,
public frmMain()
{
InitializeComponent();
}
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
ja das dachte ich mir schon, dass er das Teil deshalb wegräumt weil es "nicht mehr benötigt" wird.
Doch das Problem ist ich schreibe eine Bibliothek und da ist es nicht tragbar wenn das Zeug einfach weggeräumt wird. Deshalb kann man nicht innerhalb der Klasse dem GC verbieten sich an der Klasse zu schaffen zu machen.
Außerdem welche Anhaltspunkte ich habe... nun ja ich denke mal es ist die einzige logische Lösung.
Ich fahre das Programm nicht herunter und Zerstöre es nirgends. Von dem her kann es nur durch Zauberhand zerstört werden oder über den GC.
Hallo thefiloe,
ich denke dein "Ich benötige das Object" noch und das C# "Ich benötige das Object noch" sind 2 verschiedene paar Schuhe.
wenn du folgendes schreibst:
string s;
{
int i = 5;
s = i.ToString();
}
Ausserhalb der Klammer sagst C# von sich: Ich brauch i
nicht mehr. Wenn du es selbst aber noch benötigst, musst du den scope (also die Sichtbarkeit) wie gfoidl sagte "vergrößern".
Gruß
Michael
also kann man den GC also nicht dazu anweisen das object stehen zu lassen.
Sprich wie jetzt z.B. in nem Konstruktor dass du sagst GC.Lassesstehen(this);
Nö aber du kannst den verwender deiner Bibliothek anweisen, Instanzen des Objektes als Klassenmember zu nutzen. Wenn du dies so fest Dokumentierst, ist er selbst schuld, wenn ers nicht macht.
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |
Hallo allersiets
die Referenzen müssen doch trotzdem erhalten bleiben, also wenn ich WAVOut die Referenz auf die MP3-Datei übergebe, muß es doch dort intern eine Referenz auf die MP3-Datei geben, damit sie auch abgespielt werden kann. Das würde bedeuten, daß der GC den Speicher nicht freigibt. Daher kann ich die Schlußfolgerung mit dem Feld nicht ganz nachvollziehen.
Von daher wäre mal ein dahingehendes Feedback vom OP ganz nützlich
Christian
Weeks of programming can save you hours of planning
Deshalb kann man nicht innerhalb der Klasse dem GC verbieten sich an der Klasse zu schaffen zu machen.
Der GC schafft nichts weg, worauf noch eine erreichbare (!) Referenz zeigt.
Insofern:
also wenn ich WAVOut die Referenz auf die MP3-Datei übergebe, muß es doch dort intern eine Referenz auf die MP3-Datei geben,
Diese existiert zwar, aber wenn WAVOut nicht mehr erreichbar ist, besteht auch keine Notwendigkeit mehr, die Datei "am Leben" zu halten; der GC räumt beide auf.
Aber auf _waveOut wird doch nicht mehr verwiesen oder.
Das ist in dem Sinne egal: Man kriegt zwar eine Warnung, die aussagt, dass man das Feld nur zuweist, in diesem Fall kann man diese aber ignorieren (bzw. fixen, indem man IDisposable implementiert, da man WAVOut garantiert disposen muss).
Entscheidend ist nur, dass man noch darauf zugreifen könnte.
Daher kann ich die Schlußfolgerung mit dem Feld nicht ganz nachvollziehen.
Macht man aus waveOut ein Feld (für die Datei braucht man nicht zwangsläufig eins), ist die Referenz auch nach Verlassen der Methode noch erreichbar - folglich räumt der GC nichts weg.
GC.Lassesstehen(this);
Und was sollte das bringen (außer, ein Memoryleak zu erzeugen)?
Hallo thefiloe,
nur der vollständigkeithalber:
GC.Lassesstehen(this);
Sowas ginge mit GC.KeepAlive Method (System), allerdings ist das hier nicht nötig und sogar schlecht (mehr ein Hack als Code), denn es gibt viel bessere Möglichkeiten. Diese wurden auch in diesem Thread schon (mehrfach) erwähnt.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Sowas ginge mit
>
Nein, auch da räumt der GC nach Aufruf der Methode auf.
Im Prinzip ist GC.KeepAlive nichts weiter als eine normale, leere Methode, die - alleine durch die Übergabe des Objekts als Parameter - sicherstellt, dass das Objekt auf jeden Fall bis zum Aufruf der Methode "überlebt".
Kleines Beispiel, wofür man KeepAlive brauchen kann:
public static void Main()
{
Timer timer = new Timer(Tick, null, 0, 1000);
//GC.KeepAlive(timer);
Console.ReadLine();
//GC.KeepAlive(timer);
}
private static void Tick(object state)
{
Console.WriteLine("Tick!");
GC.Collect(); //Kann man theoretisch auch weglassen - macht das Ergebnis nur etwas offensichtlicher
}
Je nachdem, welches der beiden KeepAlive man auskommentiert, verhält sich das Programm anders:
Beim oberen KeepAlive wird nur einmal (oder theoretisch keinmal) "Tick" ausgegeben, beim zweiten jede Sekunde (wie erwartet).
Nach dem Aufruf verändert sich aber absolut gar nichts daran, wie der GC das Objekt behandelt.
Hallo winSharp93,
das widerspricht ja nicht meiner Antwort. Das was du erklärt hast steht genauso im Link. Und dass der Code hackmäßig zu ändern ist, damit KeepAlive greift hab ich auch erwähnt.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
das widerspricht ja nicht meiner Antwort.
Doch: thefiloe hat mit dem "GC.Lassesstehen" nach einer Methode gesucht, die ein Objekt auch nach Ausführung der Methode ohne Verwendung eines Feldes am Leben hält (quasi als ob man etwas einfach in einem statischen Feld speichert).
Aber genau das macht KeepAlive eben nicht: Insofern könnte man GC.KeepAlive auch noch so oft in dem ursprünglichen Code aufrufen: Das Problem würde damit immer noch bestehen, es würde alles beim alten bleiben.
KeepAlive hält eben nicht dauerhaft, sondern nur bis zum Aufruf "am Leben".
GC.KeepAlive zu verwenden wäre also kein Hack (von einem solchen kann man m.E. nur sprechen, wenn er auch tatsächlich das gewünschte Ergebnis liefert) und somit auch keine Alternative (auch keine schlechte).
@winsharp93
Danke für die gute erklärung von GC.KeepAlive() , hatte mich schonmal gewundert warum es nicht so funktioniert wie schon von vielen missverständlich eklärt und von mir immer falsch verstanden...
Es müsste eigentlich GC.KeptAliveUntilHere() heissen. 😉
@winsharp93
Danke für die gute erklärung von GC.KeepAlive()
Genau, jetzt hab ich's auch verstanden 😃
Also wäre doch die einfachste (oder einzige?) Lösung die Verwendung eines Feldes, was sollte also dagegensprechen, es so zu machen?
Schöne Grüße,
Christian
Weeks of programming can save you hours of planning
Also wäre doch die einfachste (oder einzige?) Lösung die Verwendung eines Feldes, was sollte also dagegensprechen, es so zu machen?
Ja, genau. Dagegen spricht auch absolut nichts 😉
Man muss nur aufpassen, dass man das Feld nicht versehentlich "wegoptimiert", da es ja scheinbar nie ausgelesen wird - also unbedingt ein Kommentar bzw. ein Attribut zu Dokumentationszwecken anbringen.
Daher auch mein Hinweis auf IDisposable - diese Schnittstelle zu implementieren, macht in diesem konkreten Zusammenhang sicherlich Sinn und nebenbei verwendet man das Feld dann auch tatsächlich für etwas 🙂
Hallo zusammen,
die reine Existenz einer Referenz ist sowie so nicht ausreichend. Der GC kann auch Objekte, die noch referenziert werden, entfernen, wenn er erkennen kann, dass die Referenz im Code nicht mehr angesprochen wird.
Siehe dazu auch MemoryLeaks / nicht abgehängte Events.
herbivore
Der GC kann auch Objekte, die noch referenziert werden, entfernen, wenn er erkennen kann, dass die Referenz im Code nicht mehr angesprochen wird.
...wobei bei einer Referenzierung durch eine Instanzvariable das ausgeschlossen sein sollte (vorausgesetzt die Instanz, welche die Variable hält, ist auch entsprechend erreichbar) - sonst könnte man ja per Reflection evtl. Referenzen auf bereits collectete Objekte erhalten.