WPF memory allocation using bindings, inotifypropertychanged property and dependency

I am writing a program that uses a bunch of two-way bindings, and the amount of memory used has become a huge problem. In my full application, I start with 50 MB, and then just using the bindings (i.e., changing the value on the one hand and allowing the binding to be updated on the other hand), I usually break 100 MB, although my code does not highlight anything new, My the question is what is additional memory and what can I do to control it. I created a simple, reproducible example below:

Let's say I have a main window with the following contents:

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

And then in this window constructor I create a new window, show it, and then bind its WidthProperty and HeightProperty dependency properties to variables that use 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(); } } 

Then, if I constantly resize the window, my memory usage in the task manager increases linearly without a visible upper limit. The program starts with 17 MB, and within 30 seconds after changing it, it increases to 20 MB and soars after a certain point in low 20 (thanks Jan). This happens even if there are no bindings and memory is not returned. Although this is annoying, it is not the β€œleap of memory" that I am talking about.

If I uncomment the lines that also bind text fields to variables, I get the following result: in just a few seconds it jumps from 18 MB to 38 MB, and then it floats there (note the setting of binding for the text field in XAML does not affect the splash memory). I tried to implement my own converter to bind a text field, but this does not affect memory usage.

A jump still exists if I change the variables to new dependency properties and bind to them, for example.

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

or if I bind directly between the text property and the width dependency property and use BindingMode.OneWay or vice versa.

Using the CLR profiler does not seem to show me what is being allocated, and I do not have access to the commercial memory profiler. Can someone explain to me what is stored in memory, and how can I get rid of it while maintaining the functionality of a continuous BindingMode? Should I implement my own binding method and handle events myself? Or is there something I can regularly hide outside of the GC?

Thank you for your time.

+4
source share
2 answers

One thing to keep in mind with simple programs like this is that a small amount of code can get into a fairly large amount of WPF infrastructure. For example, with a single TextBox you use the layout engine, property engine, template system, styling system, and accessibility features. The moment you start typing, you are also introducing an input system, typography support, and some non-trivial internationalization infrastructure.

Those last two can be a big part of what you see in this particular example. WPF automatically uses many of the features of the OpenType font, which requires it to do a lot of work under covers. (As it happens, the default UI font doesn't really do much with it, but you still end up paying the price for entering code that discovers that the Segoe user interface is not a very interesting font.) This is a relatively expensive feature to say how subtle the difference. It's just as amazing how much goes into processing locally-compatible input β€” getting it fully rights with full i8n support is more work than most people imagine.

You will probably pay a price for each of these subsystems, because the TextBox not the only WPF element to use them. Thus, the effort required for manual solutions that try to avoid them can ultimately be a gift.

Tiny test applications paint a misleading picture - in a real application, the price you paid shares a little better. Your first TextBox might have cost 30 MB, but now you have downloaded all the content that the rest of your application will use anyway. If you started with an application that uses nothing but a ListBox , you can add a TextBox and compare the difference in memory consumption with a baseline ListBox . This will probably give you a pretty different picture of the marginal cost of adding a TextBox to your application.

Thus, outside the context of a trivial test application, the effort required to write your own text field is likely to have very few differences in private working set in practice. You will almost certainly finish paging in all the functions and systems that I mentioned in the first paragraph, because the TextBox is not the only thing that can be used in WPF.

Can each of these systems be more economical? Without a doubt, they could, but, unfortunately, WPF did not have as many engineering materials as I would like with the distraction of Silverlight, not to mention the fact that Win8 made another attempt to create a user interface. High memory usage, unfortunately, is a feature of WPF. (Although keep in mind that the WPF application will also use more memory on a machine with more memory. It requires some memory pressure before its working set is brought to the most efficient level.)

+2
source

I am really confused by this ... I thought I checked everything and tried as many approaches as possible, but I did not think that the burst of memory was from the TextBox itself . This is what causes the surge. If you remove all the bindings and fluff and just get a TextBox, even if their UndoLimit is set to zero and limits MaxLength, the program memory still increases by 15Mb + after a dozen or so changes to the contents of the TextBox. Since the bindings also updated the text box, they caused this splash. I know that default controls should cover a wide variety of uses, but, like my first C # / WPF program, I did not understand how inflated they really are in this case. I'm going to write my own TextBox control and remind myself to never take too much when it comes to that. But at least I can put my binding code aside now!

0
source

All Articles