gpt4 book ai didi

WPF 内存分配使用绑定(bind)、inotifypropertychanged 和依赖属性实现飞跃

转载 作者:行者123 更新时间:2023-12-05 00:10:51 25 4
gpt4 key购买 nike

我正在编写一个使用一堆双向绑定(bind)的程序,并且使用的内存量已成为一个大问题。在我的完整应用程序中,我从 50Mb 开始,然后,仅通过使用绑定(bind)(即更改一侧的值并让绑定(bind)更新另一侧),我通常会打破 100Mb,即使我的代码没有分配任何新内容.我的问题是这个额外的内存是什么以及我可以做些什么来控制它。我在下面创建了一个简单的、可重现的示例:

假设我有一个包含以下内容的主窗口:

<StackPanel Height="25" Orientation="Horizontal">
<TextBox UndoLimit="1" Name="TestWidth" />
<Label>,</Label>
<TextBox UndoLimit="1" Name="TestHeight" />
</StackPanel>

然后在这个窗口的构造函数中,我生成一个新窗口,显示它,然后将它的 WidthProperty 和 HeightProperty 依赖属性绑定(bind)到利用 INotifyPropertyChanged 的​​变量:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private int _WidthInt;
public int WidthInt
{
get { return _WidthInt; }
set { _WidthInt = value; NotifyPropertyChanged("WidthInt"); }
}

private int _HeightInt;
public int HeightInt
{
get { return _HeightInt; }
set { _HeightInt = value; NotifyPropertyChanged("HeightInt"); }
}

public MainWindow()
{
InitializeComponent();
Window testWindow = new Window();
testWindow.Show();

Binding bind = new Binding("HeightInt");
bind.Source = this;

bind.Mode = BindingMode.TwoWay;
testWindow.SetBinding(Window.HeightProperty, bind);
//bind.Converter = new convert();
//this.TestHeight.SetBinding(TextBox.TextProperty, bind);

bind = new Binding("WidthInt");
bind.Source = this;

bind.Mode = BindingMode.TwoWay;
testWindow.SetBinding(Window.WidthProperty, bind);
//bind.Converter = new convert();
//this.TestWidth.SetBinding(TextBox.TextProperty, bind);
}

public event PropertyChangedEventHandler PropertyChanged;

protected void NotifyPropertyChanged(string sProp)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(sProp));
GC.Collect();
}
}

然后,如果我不断调整窗口大小,我在任务管理器中的内存使用量会线性增加,没有明显的上限。该程序从 17Mb 开始,在调整大小后 30 秒内增加到 20Mb 并在 20 的某个点后悬停(感谢 Ian)。即使没有绑定(bind),这实际上也会发生,并且内存不会回退。虽然很烦人,但这不是我所说的“内存飞跃”。

如果我取消注释也将文本框绑定(bind)到变量的行,我会得到以下结果:在短短几秒钟内,它从 18Mb 跳转到 38Mb,然后悬停在那里(请注意在 XAML 中设置文本框的绑定(bind)不会影响内存峰值)。我尝试为文本框绑定(bind)实现自己的转换器,但这不会影响内存使用。

如果我将变量更改为新的依赖属性并绑定(bind)到它们,跳转仍然存在,例如
    public static readonly DependencyProperty WidthIntProperty = DependencyProperty.Register("WidthIntProperty", typeof(int), typeof(MainWindow), new UIPropertyMetadata(0, null));
int WidthInt
{
get { return (int)this.GetValue(WidthIntProperty); }
set { this.SetValue(WidthIntProperty, value); }
}
...
Binding bind = new Binding("Text");
bind.Source = TestHeight;
bind.Mode = BindingMode.TwoWay;
this.SetBinding(MainWindow.HeightIntProperty, bind);
testWindow.SetBinding(Window.HeightProperty, bind);

或者如果我直接在 text 属性和 width 依赖属性之间绑定(bind)并使用 BindingMode.OneWay 或反之亦然。

使用 CLR 分析器似乎无法向我显示分配的内容,并且我无权访问商业内存分析器。有人可以向我解释一下内存中保存了什么以及如何在仍然具有连续 BindingMode 的功能的同时摆脱它吗?我是否必须实现自己的绑定(bind)方法并自己处理事件?或者有什么我可以定期在 GC 之外冲洗的东西吗?

感谢您的时间。

最佳答案

像这样的简单程序要记住的一件事是,少量代码最终可能会影响相当大量的 WPF 基础结构。例如,使用单个 TextBox您正在使用布局引擎、属性引擎、模板系统、样式系统和辅助功能。在您开始打字的那一刻,您还引入了输入系统、排版支持和一些重要的国际化基础设施。

最后两个很可能是您在这个特定示例中看到的大部分内容。 WPF 自动利用了很多 OpenType 字体功能,这需要它在幕后做很多工作。 (碰巧默认的 UI 字体实际上并没有用它做很多事情,但你最终还是要为发现 Segoe UI 不是一个非常有趣的字体的代码付出代价。)它是一个相对昂贵的功能说它产生了多么微妙的差异。同样,区域感知输入处理投入了如此多的工作量令人惊讶——在完全支持 i8n 的情况下全面正确地完成这项工作比大多数人想象的要多。

您最终可能会为这些子系统中的每一个付出代价,因为 TextBox不是唯一使用它们的 WPF。因此,试图避免它们的手工构建解决方案所需的努力最终可能是徒劳的。

微小的测试应用程序描绘了一幅误导性的画面——在实际应用程序中,所付出的代价会更好地分摊。您的第一个 TextBox可能已经花费了您的 30MB,但是您现在已经分页加载了应用程序的其余部分无论如何都会使用的内容。您是否从只使用 ListBox 的应用程序开始? ,然后您可以添加 TextBox并将内存消耗的差异与 ListBox 进行比较- 仅基线。这可能会让您对添加 TextBox 的边际成本有完全不同的了解。到您的应用程序。

因此,在琐碎的测试应用程序的上下文之外,编写自己的文本框所需的工作可能在实践中对私有(private)工作集产生很小的影响。几乎可以肯定,你最终会在第一段中提到的所有功能和系统中分页,因为 TextBox不是 WPF 中唯一使用它们的东西。

这些系统中的每一个都可以更节俭吗?毫无疑问,他们可以,但遗憾的是,WPF 并没有我想要的那么多工程投入,Silverlight 会让人分心,更不用说在 Win8 中再次尝试 UI 框架的谣言了。 . 不幸的是,高内存使用率是 WPF 的一个特性。 (尽管请记住,WPF 应用程序也倾向于在具有更多内存的机器上使用更多内存。在其工作集被驱动到最有效的水平之前需要一些内存压力。)

关于WPF 内存分配使用绑定(bind)、inotifypropertychanged 和依赖属性实现飞跃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6523666/

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