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
Garbage Collector zerstört Objekt obwohl er nicht soll
thefiloe
myCSharp.de - Member



Dabei seit:
Beiträge: 94

Themenstarter:

Garbage Collector zerstört Objekt obwohl er nicht soll

beantworten | zitieren | melden

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();
        }

    }
}
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5985
Herkunft: Leipzig

beantworten | zitieren | melden

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

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7559
Herkunft: Waidring

beantworten | zitieren | melden

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



Dabei seit:
Beiträge: 94

Themenstarter:

beantworten | zitieren | melden

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

Avatar #avatar-3236.jpg


Dabei seit:
Beiträge: 1626
Herkunft: Südtirol/Italien

beantworten | zitieren | melden

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
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von xxMUROxx am .
Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp
private Nachricht | Beiträge des Benutzers
thefiloe
myCSharp.de - Member



Dabei seit:
Beiträge: 94

Themenstarter:

beantworten | zitieren | melden

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

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2358

beantworten | zitieren | melden

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 | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5985
Herkunft: Leipzig

beantworten | zitieren | melden

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



Dabei seit:
Beiträge: 161

beantworten | zitieren | melden

Aber auf _waveOut wird doch nicht mehr verwiesen oder.
private Nachricht | Beiträge des Benutzers
winSharp93
myCSharp.de - Experte

Avatar #avatar-2918.png


Dabei seit:
Beiträge: 6155
Herkunft: Stuttgart

beantworten | zitieren | melden

Zitat von thefiloe
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:
Zitat
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.
Zitat
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.
Zitat
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.
Zitat
GC.Lassesstehen(this);
Und was sollte das bringen (außer, ein Memoryleak zu erzeugen)?
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7559
Herkunft: Waidring

beantworten | zitieren | melden

Hallo thefiloe,

nur der vollständigkeithalber:
Zitat
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!"
private Nachricht | Beiträge des Benutzers
winSharp93
myCSharp.de - Experte

Avatar #avatar-2918.png


Dabei seit:
Beiträge: 6155
Herkunft: Stuttgart

beantworten | zitieren | melden

Zitat von gfoidl
Sowas ginge mit GC.KeepAlive Method (System)
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.
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7559
Herkunft: Waidring

beantworten | zitieren | melden

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

Avatar #avatar-2918.png


Dabei seit:
Beiträge: 6155
Herkunft: Stuttgart

beantworten | zitieren | melden

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



Dabei seit:
Beiträge: 105

beantworten | zitieren | melden

@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.
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5985
Herkunft: Leipzig

beantworten | zitieren | melden

Zitat von rasepretrep
@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
private Nachricht | Beiträge des Benutzers
winSharp93
myCSharp.de - Experte

Avatar #avatar-2918.png


Dabei seit:
Beiträge: 6155
Herkunft: Stuttgart

beantworten | zitieren | melden

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

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

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

Avatar #avatar-2918.png


Dabei seit:
Beiträge: 6155
Herkunft: Stuttgart

beantworten | zitieren | melden

Zitat von 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.
private Nachricht | Beiträge des Benutzers