我有一個使用TextBox將消息記錄到屏幕的應用程序。更新函數使用一些Win32函數來確保該框自動滾動到最後,除非用戶正在查看另一行。這裏是更新功能:自動滾動文本框使用比預期更多的內存
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);
}
}
}
現在奇怪的是,文本框消耗至少是我期望的內存的兩倍。例如,當TextBox中有大約1MB的消息時,應用程序可以消耗多達6MB的內存(除了將logToScreen設置爲false時使用的內容之外)。這個增長總是至少是我期望的兩倍,並且(如我的例子)有時更多。
什麼是更奇怪的是,使用:
this.txtBoxLogging.Clear();
for (int i = 0; i < 3; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
不釋放內存(事實上,它略有增加)。
任何想法在記錄這些消息時記憶正在發生?我不相信它與Win32調用有任何關係,但我已經將它包括在內了。
編輯:
我得到的第一對夫婦的反應是涉及到如何跟蹤內存泄漏,所以我想我應該分享我的方法。我使用了WinDbg和perfmon的組合來隨着時間的推移(從幾個小時到幾天)跟蹤內存的使用情況。所有CLR堆的總字節數並沒有增加超過我的預期,但隨着更多的消息被記錄,專用字節的總數穩步增加。這使得WinDbg不太有用,因爲它的工具(sos)和命令(dumpheap,gcroot等)基於.NET的託管內存。
這可能是爲什麼GC.Collect()不能幫助我,因爲它只是在CLR堆上尋找空閒內存。我的泄漏似乎在未被管理的內存中。
先生,你是我的救命恩人!最後,TextboxBase追加滾動鎖定工作! – 2010-02-28 14:48:56
有趣的提示:使用richTextBox.Text + = str而不是richTextBox.AppendText(str)消除了閃爍,但是當字符串變大時導致大量減速 – 2010-03-01 09:07:41