下午好。幫助解決以下問題。如果我為DataGrid.ItemsSource設定了一些DataTable,我將在另一個執行緒中更新它,然后定期呼叫DataGrid.Items.Refresh()我將有記憶體泄漏。有沒有辦法避免這種情況?
<Window x:Class="TestDataGrid.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestDataGrid"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="7*"/>
</Grid.ColumnDefinitions>
<DataGrid x:Name="DataGrid1" d:ItemsSource="{d:SampleData ItemCount=5}" Grid.ColumnSpan="2"/>
</Grid>
</Window>
主視窗
using System;
using System.Windows;
namespace TestDataGrid
{
public partial class MainWindow : Window
{
DataWorker data = new DataWorker();
public MainWindow()
{
InitializeComponent();
DataGrid1.ItemsSource = data.dt.DefaultView;
data.DataChanged = OnDataChanged;
data.RunThread();
}
private void OnDataChanged(object obj, EventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
DataGrid1.Items.Refresh();
//this.Title = data.dt.Rows[0].ItemArray[0].ToString();
}));
}
}
}
DataWorker.cs
using System;
using System.Data;
using System.Threading;
namespace TestDataGrid
{
internal class DataWorker
{
public event EventHandler DataChanged;
public DataWorker()
{
column.DataType = Type.GetType("System.UInt64");
column.ColumnName = "DATA";
dt.Columns.Add(column);
}
public DataTable dt = new DataTable();
private DataColumn column = new DataColumn();
public void RunThread()
{
Thread th = new Thread(DataChange);
th.Start();
}
private void DataChange()
{
while (true)
{
dt.Clear();
dt.Rows.Add(new object[] { DateTime.Now.Ticks });
DataChanged?.Invoke(this, EventArgs.Empty);
Thread.Sleep(1000);
}
}
}
}
例如,如果我將DataGrid1.Items.Refresh()更改為 this.Title = data.dt.Rows[0].ItemArray[0].ToString(),則記憶體正常。
開始畫面
2 分鐘后螢屏
專案:GitHub
uj5u.com熱心網友回復:
不知道如何
this.Title = data.dt.Rows[0].ItemArray[0].ToString();
涉及到
DataGrid1.Items.Refresh();
這是針對兩個不同目標物件的兩種不同操作。
以下只是將單元格值分配給Window.Title屬性:
this.Title = data.dt.Rows[0].ItemArray[0].ToString();
然而
DataGrid1.Items.Refresh();
指示DataView重新創建視圖。這意味著快取資料被丟棄,但仍駐留在記憶體中。垃圾收集器收集這些符合要求的物件需要時間。
這不是記憶體泄漏。
有一些嚴肅的事情在進行CollectionView.Refresh。
僅僅因為它是單行代碼并不意味著您可以將其指標與任何隨機代碼行進行比較。
如果記憶體使用對您來說是個問題,請考慮使用 aObservableCollection而不是DataTable.
如果您描述的場景是真實場景,那么使用 aObservableCollection比使用DataTable單行單列的 a更方便。在您的情況下,您可以將時間戳直接添加到ObservableCollection.
一些改進代碼的建議:
- 不要使用
Thread和Thread.Sleep。總是使用現代的Task.Run,await Task.Delay而不是 - 避免
while(true)構造 - 使用定時器進行周期性操作
- 不要定義公共欄位。改用屬性。在您的情況下,該屬性應該是只讀的。
- 身高委托
EventHandler過EventHandler<EventArgs>:
event EventHandler MyEvent;
超過
event EventHandler<EventArgs> MyEvent;
改進后的實作如下所示:
DataWorker.cs
internal class DataWorker
{
private DispatcherTimer Timer { get; }
public DataTable Dt { get; } = new DataTable();
private DataColumn Column { get; } = new DataColumn();
public event EventHandler DataChanged;
public DataWorker()
{
this.Column.DataType = Type.GetType("System.UInt64");
this.Column.ColumnName = "DATA";
this.Dt.Columns.Add(this.Column);
this.Timer = new DispatcherTimer(
TimeSpan.FromSeconds(1),
DispatcherPriority.Normal,
OnTimerElapsed,
Application.Current.Dispatcher);
}
private void OnTimerElapsed(object? sender, EventArgs e)
{
this.Dt.Clear();
this.Dt.Rows.Add(new object[] { DateTime.Now.Ticks });
this.DataChanged?.Invoke(this, EventArgs.Empty);
}
}
主視窗.xaml.cs
public MainWindow(TestViewModel dataContext)
{
var data = new DataWorker();
DataGrid.ItemsSource = data.dt.DefaultView;
data.DataChanged = OnDataChanged;
}
private void OnDataChanged(object obj, EventArgs e)
{
DataGrid.Items.Refresh();
}
如何識別記憶體泄漏
僅觀察總記憶體分配是不夠的。記憶體分配隨時間增加的原因有很多。記憶體泄漏的特征是記憶體包含永遠不會被收集的物件,因為它們總是可訪問的。造成這種情況的原因各不相同。這可能是因為事件源、資料系結等的靜態參考或物件生命周期管理。
要識別泄漏,您必須檢查堆上的物件。您可以通過比較記憶體的快照來做到這一點。并通過像這樣強制垃圾收集:
for (int i = 0; i < 4; i )
{
GC.Collect(2, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
}
如果物件仍在堆上,盡管您希望它們被收集,因為您已經洗掉了所有參考,那么您可能存在泄漏。
每個好的分析器都允許您擴展參考樹以識別導致物件可達的類。您必須檢查此類以找到強參考的原因。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/393086.html
上一篇:在派生控制元件中隱藏基類依賴屬性
