nếu bạn làm việc trên một số ứng dụng wpf lớn hơn, bạn có thể quen thuộc với this. Bởi vì ResourceDictionaries luôn được khởi tạo, mỗi khi chúng được tìm thấy trong XAML, chúng ta có thể sẽ có một từ điển tài nguyên nhiều lần trong bộ nhớ. Vì vậy, các giải pháp được đề cập ở trên có vẻ như là một lựa chọn rất tốt. Trong thực tế cho dự án hiện tại của chúng tôi lừa này đã làm rất nhiều ... Bộ nhớ tiêu thụ từ 800mb xuống 44mb, đó là một tác động thực sự rất lớn. Rất tiếc, giải pháp này có chi phí mà tôi muốn hiển thị ở đây và hy vọng tìm cách tránh nó trong khi vẫn sử dụng SharedResourceDictionary
.Rò rỉ bộ nhớ khi sử dụng SharedResourceDictionary
Tôi đã tạo một ví dụ nhỏ để trực quan hóa vấn đề bằng từ điển tài nguyên được chia sẻ.
Chỉ cần tạo một ứng dụng WPF đơn giản. Thêm một nguồn XAML
Shared.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="myBrush" Color="Yellow"/>
</ResourceDictionary>
Bây giờ thêm một usercontrol. Codebehind chỉ là mặc định, vì vậy tôi chỉ hiển thị XAML
MyUserControl.xaml
<UserControl x:Class="Leak.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:SharedResourceDictionary="clr-namespace:Articy.SharedResourceDictionary" Height="128" Width="128">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Leak;component/Shared.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Rectangle Fill="{StaticResource myBrush}"/>
</Grid>
</UserControl>
Mã Window đằng sau trông giống như sau
Window1.xaml.cs
// [ ... ]
public Window1()
{
InitializeComponent();
myTabs.ItemsSource = mItems;
}
private ObservableCollection<string> mItems = new ObservableCollection<string>();
private void OnAdd(object aSender, RoutedEventArgs aE)
{
mItems.Add("Test");
}
private void OnRemove(object aSender, RoutedEventArgs aE)
{
mItems.RemoveAt(mItems.Count - 1);
}
Và cửa sổ xaml như thế này
Window1.XAML
<Window.Resources>
<DataTemplate x:Key="myTemplate" DataType="{x:Type System:String}">
<Leak:MyUserControl/>
</DataTemplate>
</Window.Resources>
<Grid>
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Button Content="Add" Click="OnAdd"/>
<Button Content="Remove" Click="OnRemove"/>
</StackPanel>
<TabControl x:Name="myTabs" ContentTemplate="{StaticResource myTemplate}">
</TabControl>
</DockPanel>
</Grid>
</Window>
Tôi biết chương trình là không hoàn hảo và propably thể được thực hiện dễ dàng hơn nhưng trong khi tìm ra một cách để hiển thị các vấn đề này là những gì tôi đã đưa ra. Dù sao:
Bắt đầu điều này và bạn kiểm tra mức tiêu thụ bộ nhớ, nếu bạn có trình thu thập bộ nhớ, việc này trở nên dễ dàng hơn nhiều. Thêm (với hiển thị nó bằng cách nhấp vào tab) và xóa một trang và bạn sẽ thấy mọi thứ hoạt động tốt. Không có gì rò rỉ. Bây giờ, trong mục UserControl.Resources
, hãy sử dụng SharedResourceDictionary
thay vì ResourceDictionary
để bao gồm Shared.xaml. Bạn sẽ thấy rằng MyUserControl
sẽ được lưu trong bộ nhớ sau khi bạn xóa một trang và MyUserControl
trong đó.
Tôi nhận thấy điều này xảy ra với mọi thứ được khởi tạo qua XAML như trình chuyển đổi, điều khiển người dùng, vv Điều lạ lùng sẽ không xảy ra với Kiểm soát tùy chỉnh. Tôi đoán là, bởi vì không có gì thực sự được khởi tạo trên các điều khiển tùy chỉnh, các mẫu dữ liệu và vân vân.
Vì vậy, trước tiên chúng ta có thể tránh điều đó như thế nào? Trong trường hợp của chúng tôi bằng cách sử dụng SharedResourceDictionary là phải, nhưng rò rỉ bộ nhớ làm cho nó không thể sử dụng nó một cách hiệu quả. Rò rỉ có thể tránh được bằng cách sử dụng CustomControls thay vì UserControls, không phải lúc nào cũng thực tế. Vậy tại sao UserControls được tham chiếu mạnh mẽ bởi ResourceDictionary? Tôi tự hỏi tại sao không ai có kinh nghiệm này trước đây, như tôi đã nói trong một câu hỏi cũ, có vẻ như chúng ta sử dụng từ điển tài nguyên và XAML hoàn toàn sai, nếu không tôi tự hỏi tại sao chúng lại không hiệu quả.
Tôi hy vọng ai đó có thể làm sáng tỏ vấn đề này.
Cảm ơn trước Nico
Trong hồ sơ bộ nhớ của bạn, đối tượng nào giữ tham chiếu đến cá thể MyUserControl? –
Tôi không thể nhớ chắc chắn, nhưng tôi gần như chắc chắn nó là một ResourceDictionary, tốt trong trường hợp của tôi một SharedResourceDictionary. – dowhilefor