gpt4 book ai didi

wpf - 使用 SharedResourceDictionary 时出现内存泄漏

转载 作者:行者123 更新时间:2023-12-04 00:45:16 26 4
gpt4 key购买 nike

如果您使用过一些较大的 wpf 应用程序,您可能会熟悉 this .因为 ResourceDictionaries 总是被实例化,所以每次在 XAML 中找到它们时,我们最终可能会在内存中多次拥有一个资源字典。所以上面提到的解决方案似乎是一个很好的选择。事实上,对于我们当前的项目,这个技巧做了很多......内存消耗从 800mb 减少到 44mb,这是一个非常巨大的影响。不幸的是,这个解决方案是有代价的,我想在这里展示,并希望找到一种方法来避免它,同时仍然使用 SharedResourceDictionary .

我做了一个小例子,用共享资源字典来形象化这个问题。

只需创建一个简单的 WPF 应用程序。添加一个资源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>

现在添加一个用户控件。代码隐藏只是默认值,所以我只显示 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>

后面的窗口代码看起来像这样

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);
}

和这样的窗口 xaml

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>

我知道该程序并不完美,并且可能会变得更容易,但是在想出一种方法来显示问题的同时,这就是我想出的。无论如何:

启动它并检查内存消耗,如果您有内存分析器,这会变得容易得多。添加(通过单击选项卡显示它)并删除一个页面,您将看到一切正常。没有任何泄漏。
现在在 UserControl.Resources部分使用 SharedResourceDictionary而不是 ResourceDictionary包括 Shared.xaml。你会看到 MyUserControl删除页面后将保留在内存中, MyUserControl在其中。

我认为这会发生在通过 XAML 实例化的所有东西上,例如转换器、用户控件等。奇怪的是,这不会发生在自定义控件上。我的猜测是,因为在自定义控件、数据模板等上没有真正实例化。

那么首先我们如何避免这种情况?在我们的例子中,使用 SharedResourceDictionary 是必须的,但是内存泄漏使得它无法有效地使用它。
使用 CustomControls 而不是 UserControls 可以避免泄漏,这实际上并不总是如此。那么为什么 ResourceDictionary 会强引用 UserControls 呢?
我想知道为什么以前没有人经历过这种情况,就像我在一个较旧的问题中所说的那样,似乎我们使用资源字典和 XAML 是完全错误的,否则我想知道为什么它们如此低效。

我希望有人可以对这个问题有所了解。

提前致谢
妮可

最佳答案

我不太确定这是否会解决您的问题。但是我在 ResourceDictionary 上遇到了类似的问题引用控件及其与懒惰的关系 hydration .这是一个 post就可以了。这段代码解决了我的问题:

public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
WalkDictionary(this.Resources);

base.OnStartup(e);
}

private static void WalkDictionary(ResourceDictionary resources)
{
foreach (DictionaryEntry entry in resources)
{
}

foreach (ResourceDictionary rd in resources.MergedDictionaries)
WalkDictionary(rd);
}
}

关于wpf - 使用 SharedResourceDictionary 时出现内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6857355/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com