我正在編寫應用程序,它將監視多臺計算機,將數據存儲在數據庫中,並將其顯示在儀表板上,每隔幾秒刷新一次。刷新WPF Toolkit折線圖時內存泄漏?
這裏是我的WPF的用戶控件創建圖表XAML來源:
<chartingToolkit:Chart x:Name="chart" BorderThickness="0" Foreground="Gray"/>
然後,我開始System.Timers.Timer刷新應用流程圖。下面是代碼片段負責刷新圖表:
private Dictionary<string, List<RamPlot>> data = new Dictionary<string, List<RamPlot>>();
void refreshChartTimer_Elapsed(object sender, ElapsedEventArgs e)
{
DateTime now = DateTime.Now;
lock (lockObject)
{
//Getting info about hosts from my storage
List<HostInfo> infos = LiveHostInfoManager.GetInstance().GetHostInfos();
this.Dispatcher.Invoke(new Action(() =>
{
foreach (HostInfo info in infos)
{
//data contains info about host, so I add new values to existing one, creating data for linechart
if (data.ContainsKey(info.HostName))
{
data[info.HostName].Add(new RamPlot(DateTime.Now, (info.RamInfo.TotalSize - info.RamInfo.CurrentlyAvailable)/info.RamInfo.TotalSize));
//I want to display on chart only last 20 readings
if (data[info.HostName].Count > 20)
{
data[info.HostName].RemoveAt(0);
}
}
else
{
//If the host is not in my dictionary (connected before last iteration was performed), I add it to my dictionary
if (info.RamInfo != null)
{
List<RamPlot> plot = new List<RamPlot>();
//Thought, that it can be due to List's load factor, hence I set up capacity. Apparently - not.
plot.Capacity = 25;
plot.Add(new RamPlot(DateTime.Now, (info.RamInfo.TotalSize - info.RamInfo.CurrentlyAvailable)/info.RamInfo.TotalSize));
data.Add(info.HostName, plot);
}
}
}
//for hosts that are no longer available, I perform cleanup to get rid of them from my linechart
List<string> keysToDelete = new List<string>();
foreach (KeyValuePair<string, List<RamPlot>> kvp in data)
{
bool exists = false;
foreach (HostInfo info in infos)
{
if (info.HostName.Equals(kvp.Key))
{
exists = true;
break;
}
}
if (!exists)
{
keysToDelete.Add(kvp.Key);
}
}
foreach (string key in keysToDelete)
{
data.Remove(key);
}
//Here I attach my data to line chart. If I comment this block, I detect no memory leaks
foreach (KeyValuePair<string, List<RamPlot>> kvp in data)
{
bool exists = false;
foreach (LineSeries series in chart.Series)
{
if (series.Title.ToString().Equals(kvp.Key) && !string.IsNullOrEmpty(kvp.Key))
{
series.ItemsSource = null;
series.ItemsSource = kvp.Value;
exists = true;
break;
}
}
if (!exists && !string.IsNullOrEmpty(kvp.Key))
{
LineSeries series = new LineSeries();
series.Title = kvp.Key;
series.IndependentValueBinding = new Binding("Date");
series.DependentValueBinding = new Binding("Usage");
series.ItemsSource = kvp.Value;
chart.Series.Add(series);
}
}
}));
//Thought that if I recreate all data structure, some garbage might be cleaned up by GC. Apparently - not.
data = new Dictionary<string, List<RamPlot>>(data);
}
}
我不知道在啓動時連接到我的應用程序的主機數量,從而供LineSeries加入編程。
問題是,在幾分鐘後,此代碼使用的內存增長非常快(十個圖表像這樣,約15分鐘內約有400 MB)。 正如你可以在評論中看到的那樣,在所發現的問題和答案的引導下,我試圖做一些事情來防止我的應用程序的RAM使用增長,我也嘗試調整整個algorythm,但沒有成功。
目前我正在用盡想法如何解決它。應用程序應該24/7工作,它必須是穩定的。
經過一段時間尋找解決方案,我會很高興,如果你能幫我解決這個問題。
感謝您的快速回復。我試圖玩你的代碼的參數,仍然有大量的數據消耗。有趣的是,我試圖使用D3 DynamicDataDisplay圖表,效果仍然相同。而且,當我修改我的代碼以在每個'timer_elapsed'方法中調用'chart.Series.Clear()'時,結果也是一樣的 - 內存仍在增長。我開始考慮將WinForms ZedGraph加入其中,因爲我對它有着美好的回憶。 – greenskin
奇怪的是,如果間隔爲1000毫秒,則不會再現行爲。也許如果我們設置300ms的數據獲取時間超過300ms,調度器隊列開始無限增長......可惜現在沒有時間去檢查它了 – FireAlkazar