Auto-scrolling-text-Feld verwendet mehr Speicher als erwartet

Ich habe eine Anwendung, die protokolliert Meldungen auf dem Bildschirm mit einem Textfeld. Die update-Funktion verwendet einige Win32-Funktionen, um sicherzustellen, dass die box automatisch einen Bildlauf an das Ende, es sei denn, der Benutzer ist anzeigen eine weitere Zeile. Hier ist die update-Funktion:

private bool logToScreen = true;

//Constants for extern calls to various scrollbar functions
private const int SB_HORZ = 0x0;
private const int SB_VERT = 0x1;
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int SB_THUMBPOSITION = 4;
private const int SB_BOTTOM = 7;
private const int SB_OFFSET = 13;

[DllImport("user32.dll")]
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
[DllImport("user32.dll")]
static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);

private void LogMessages(string text)
{
    if (this.logToScreen)
    {
        bool bottomFlag = false;
        int VSmin;
        int VSmax;
        int sbOffset;
        int savedVpos;
        //Make sure this is done in the UI thread
        if (this.txtBoxLogging.InvokeRequired)
        {
            this.txtBoxLogging.Invoke(new TextBoxLoggerDelegate(LogMessages), new object[] { text });
        }
        else
        {
            //Win32 magic to keep the textbox scrolling to the newest append to the textbox unless
            //the user has moved the scrollbox up
            sbOffset = (int)((this.txtBoxLogging.ClientSize.Height - SystemInformation.HorizontalScrollBarHeight) / (this.txtBoxLogging.Font.Height));
            savedVpos = GetScrollPos(this.txtBoxLogging.Handle, SB_VERT);
            GetScrollRange(this.txtBoxLogging.Handle, SB_VERT, out VSmin, out VSmax);
            if (savedVpos >= (VSmax - sbOffset - 1))
                bottomFlag = true;
            this.txtBoxLogging.AppendText(text + Environment.NewLine);
            if (bottomFlag)
            {
                GetScrollRange(this.txtBoxLogging.Handle, SB_VERT, out VSmin, out VSmax);
                savedVpos = VSmax - sbOffset;
                bottomFlag = false;
            }
            SetScrollPos(this.txtBoxLogging.Handle, SB_VERT, savedVpos, true);
            PostMessageA(this.txtBoxLogging.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * savedVpos, 0);
        }
    }
}

Nun ist die seltsame Sache ist, dass das Textfeld verbraucht mindestens das doppelte der Speicher, ich würde es erwarten. Zum Beispiel, wenn dort sind ~1MB von Nachrichten in das Textfeld, kann die Anwendung verbrauchen bis zu 6MB Arbeitsspeicher (zusätzlich zu dem, was es nutzt, wenn die logToScreen ist auf false gesetzt). Die Erhöhung ist mindestens immer das doppelte, was ich erwarte, und (wie in meinem Beispiel), manchmal auch mehr.

Was ist mehr seltsam ist, dass die Verwendung von:

this.txtBoxLogging.Clear();
for (int i = 0; i < 3; i++)
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

Nicht den Speicher frei (in der Tat, es ist leicht erhöht).

Irgendeine Idee, wo der Speicher wird, wie ich bin-Protokollierung diese Nachrichten? Ich glaube nicht, dass es hat etwas zu tun mit der Win32-Aufrufe, aber ich habe es gründlich durchgeführt werden.

EDIT:

Den ersten paar Antworten, die ich bekam, waren, wie zu verfolgen ein Speicherleck, so dass ich dachte, ich sollte mein Anteil an Methodik. Ich habe eine Kombination von WinDbg und perfmon verfolgen Sie die Speichernutzung über die Zeit (von einigen Stunden bis zu Tagen). Die Gesamtanzahl der bytes auf alle CLR-Haufen nicht mehr als ich erwarte, aber die Gesamtzahl der privaten bytes, die stetig zunimmt, wenn mehr Nachrichten protokolliert werden. Dies macht WinDbg weniger nützlich, als es die tools (sos) und Befehle (dumpheap, gcroot, etc.) sind basierend auf .NET-verwalteten Speicher.

Dies ist wahrscheinlich, warum GC.Collect() kann mir nicht helfen, da Sie nur auf der Suche nach freien Speicher auf der CLR heap. Mein Leck zu sein scheint in der un-verwalteten Speicher.

  • Sie, sir, sind mein Retter! Endlich, TextboxBase Anhängen mit scroll-lock, das funktioniert !
  • Interessante Anmerkung: die Verwendung der richTextBox.Text+=str statt richTextBox-Steuerelement.AppendText(str) entfällt das flackern, verursacht aber massive Verlangsamung, wenn der string wird groß
InformationsquelleAutor cgyDeveloper | 2009-11-16
Schreibe einen Kommentar