Frage

Es scheint, wie Invoke Aufruf auf einem WinForms-Steuerelement in einem Rückruf von einem System.Threading.Timer Leck behandelt, bis der Timer angeordnet ist. Hat jemand eine Idee, wie dies zu umgehen? Ich brauche jede Sekunde für einen Wert abzufragen und die Benutzeroberfläche entsprechend aktualisieren.

Ich habe versucht, es in einem Testprojekt, um sicherzustellen, dass das war in der Tat die Ursache des Lecks, die einfach das ist folgende:

    System.Threading.Timer timer;
    public Form1()
    {
        InitializeComponent();
        timer = new System.Threading.Timer(new System.Threading.TimerCallback(DoStuff), null, 0, 500);
    }
    void DoStuff(object o)
    {
        this.Invoke(new Action(() => this.Text = "hello world"));
    }

Dies wird undicht 2 Griffe / Sekunde, wenn Sie in dem Windows-Task-Manager beobachten.

War es hilfreich?

Lösung

Invoke wirkt wie ein BeginInvoke / EndInvoke Paar, dass sie die Nachricht an den UI-Thread Pfosten, erzeugt einen Handgriff, und wartet an diesem Handgriff zu bestimmen, wenn das aufgerufene Verfahren abgeschlossen ist. Es ist dieser Griff, wird als „undicht.“ Sie können sehen, dass diese unbenannte Ereignisse Prozess Explorer die Griffe zu überwachen während die Anwendung ausgeführt wird.

Wenn IAsyncResult IDisposable ist, Entsorgung des Objekts würde den Griff zur Reinigung kümmern. Da dies nicht der Fall, erhalten die Griffe, wenn der Garbage Collector läuft gereinigt und ruft die Finalizerthread des IAsyncResult-Objekt. Sie können dies sehen durch eine GC.Collect Zugabe () nach jeweils 20 Anrufe DoStuff - die Handleanzahl alle 20 Sekunden fällt. Natürlich durch Hinzufügen Anrufe GC.Collect das Problem „zu lösen“ () ist der falsch Weg, um das Problem zu lösen; lassen Sie den Garbage Collector seine eigene Arbeit tun.

Wenn Sie nicht Notwendigkeit der Invoke Aufruf synchron zu sein, verwendet BeginInvoke statt Invoke und nicht EndInvoke nennen; das End-Ergebnis wird das gleiche tun, aber keine Griffe erstellt oder werden „durchgesickert.“

Andere Tipps

Gibt es einen Grund, warum Sie nicht einen System.Windows.Forms.Timer hier nicht verwenden können? Wenn der Zeitgeber zu dieser Form gebunden ist, werden Sie nicht einmal müssen aufzurufen.

Okay, habe ich es ein wenig mehr Zeit und es sieht aus wie es ist eigentlich nicht Griffe undicht, es ist nur die Unbestimmtheit der Garbage Collector. Ich stieß es Art und Weise bis zu 10 ms pro Tick und es würde klettert wirklich schnell und 30 Sekunden später fallen würden wieder nach unten.

, um die Theorie zu bestätigen, ich manuell GC.Collect () auf jedem Callback (Tun Sie dies nicht in realen Projekten, dies war nur zu testen, gibt es aus zahlreichen Artikel gibt darüber, warum es eine schlechte Idee) und die Handleanzahl stabil war.

Interessant -. Das ist keine Antwort, aber basierend auf Andrei Kommentar würde ich gedacht, dies wäre die gleiche Art und Weise jedoch nicht auslaufen behandelt es Leck mit der gleichen Geschwindigkeit nicht behandelt die OP erwähnt

System.Threading.Timer timer;
    public Form2()
    {
        InitializeComponent();

    }

    private void UpdateFormTextCallback()
    {
        this.Text = "Hello World!";
    }

    private Action UpdateFormText;

    private void DoStuff(object value)
    {
        this.Invoke(UpdateFormText);
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        timer = new System.Threading.Timer(new TimerCallback(DoStuff), null, 0, 500);
        UpdateFormText = new Action(UpdateFormTextCallback);
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top