views:

1306

answers:

6
+4  Q: 

WPF Memory Usage

Application:

  • WPF Application consisting of a textbox on top and a listbox below
  • Users type a string in the TextBox to find employees, and search results are displayed in the ListBox
  • ListBox uses DataTemplates to display elements (shows employee name, department, phone and a thumbnail picture.)

Implementation:

  • At application startup I query the database and retrieve all employees and related information to be shown in the ListBox. This is kept in memory the entire time.
  • After application startup, all the searchable data is in memory and searches are virtually instantaneous. All searches are performed on the data already in memory.
  • Search results are displayed in the ListBox using DataTemplates. Thumbnail picture, name, phone, department, etc, are shown in each ListBox item.

Problem:

  • At startup the memory usage is about 200MB.
  • As data is changed in the listbox, either via a new search or a simply scrolling down the listbox, memory consumption increases.
  • When users scroll down the listbox slowly, memory increases faster. As you scroll it up and down memory quickly reaches 1GB.

There are is no code creating controls manually - everything is done via data binding.

Why am I seeing this behavior? What can I do to fix it? Please help!

UPDATE: I figured out that the problem is not a memory leak. The issue here is that the listbox is creating objects to display the images of the employee and is not releasing for the garbage collector after the listboxitem gets out of the window. The CleanUpVirtualizedItem event occurs as I expected but the memory is still not released. Any ideas?

+3  A: 

First of all, +1 for having an awsome surname.

At the risk of being glib, you have a memory leak. Why not try a tool like ANTS* to track it down. They have a free trial, I've never used it but it has a good reputation.

*Other profiling tools are available.

If you don't want to get to grips with another tool, you can try something like incrementing a static member every time a class is created and decrementing it every time an instance is disposed. This will help you track down instances that are not be destroyed properly.

Noel Kennedy
I agree with Noel -- there's not enough information without either some code or some profiling.I have used Scitech's tool before, and it was very effective: http://memprofiler.com/ I think they have a free trial, and they also have some videos on their site that show how to use it.(I don't work for them or have any vested interest in them -- I just found it to be a good tool).
JMarsch
I also agree with Noel. Get a profiler like the ANTS profiler and see what's staying alive in memory. You should be able to track it down from there.
Judah Himango
+1  A: 

LOL 200MB startup and 1GB run.. More common penalty on x64 (and you will need it for bloat) is a penalty of around 64MB for startup and another 120MB for semi-advanced functionality, which is still huge and of course GC will keep adding more.

That's gotta kill the CPU and all the periphery around it in no time. Now imagine everything runs on that, all apps, and the entire OS and stack (as VS2010 surely will attempt some move in that direction).

I'd say: welcome to the modern way of bloatware mania and its ease of accessibility. No matter what you do you'll spend more time finding workarounds then following some 'universal' framework to quick and cool and well-styled and customisable apps. Sure WPF is good on paper but a waste of resource in any practical use (tons of resources and a steep learning curve).

And they said it was and still is the future (same for JDK apps which are oh-so-widespread).

Simply N.U.T.S + the most excellent example that it is not about speed (as CLR defenders will jump in with trivial examples) of managed code. It is about huge scalability impairement and machine wipeout as with every single GC and object-root environment out there.

Vote down coming.. go on disciples, you know you want to.

(and write to Obama against CO2 reduction that will not happen; perhaps multiply by 1003120x if that bandwagon keeps going the way it has. Even a Cray Jaguar wouldn't run that kind of operating environment any time in the next 20 years ).

rama-jka toti
I don't see 200MB as a problem at all. Most of it (80%) is data, so I can do something about that. I wonder about fast increasing memory usage. I hope I can do something about it.If I create a brand new WPF app, put a button, with no code, and as you click the button you can see memory increasing for nothing!
Gustavo Cavalcanti
It's same for WinForms but less obvious/cheaper.. have seen far too many kids just bind a ComboBox to reflection ie. Type and its properties and then creating a new instance as it 'looked right'.. All you have to see hear is a user going crazy because he was "just changing an option". Give a shot to a free MemProfiler and look for roots sticking around; if it is within the framework you can trace that with the .pdb/'source' for 3.5 too. But the point is for the ease-of-use and data-binding-generalism-to-oblivion, you are bound to face the same problem time and time again. Pick your poison..
rama-jka toti
A: 

I've noticed that there are some issues in WPF and .NET 3.5 SP1 w.r.t memory issues in seemingly innocuous situations.

I did find a couple of resources, but I'm not sure they would be helpful to you:

http://blog.ramondeklein.nl/?p=58

That blog post describes a situation whereupon when

  1. A style is defined in the application’s ResourceDictionary.
  2. The style uses a control template that uses media effects (i.e. DropShadowEffect).
  3. The media effect should be referenced using a StaticResource

In a nutshell, I think your solution would be to ensure that any media effects (dropshadow, etc) use static resources.

Josh E
Thanks Josh. I've seen this article but I believe it doesn't address my problem because a) All access to my resources are through using StaticResource; b) I do not use any bitmap effects and c) styles are defined in the Application's ResourceDcitionary (App.xaml).
Gustavo Cavalcanti
ah, bummer. Do you know what level the objects are being held in the GC? It obviously thinks there are extant references to the objects. Is it possible that the viewable canvas area is smaller than the actual canvas size, resulting in "off-screen" objects still being updated?
Josh E
Hi Josh,The size is not a factor because ALL of the objects are still being held. When I create the BitmapImage, if I use myBitmap.CacheOption = BitmapCacheOption.OnLoad then all images are created and I end up with 1GB of memory taken. If I don't cache, I start the app with around 200MB but as I keep scrolling, memory increases up to 1GB.
Gustavo Cavalcanti
+3  A: 

You could use

WPF Performance Suite

Optimizing WPF Application Performance

A similar issue haunts me.. (something like)

At application startup I query the database and retrieve all employees and related information to be shown in the ListBox. This is kept in memory the entire time.

May be you could modify your code to follow WPF: Data Virtualization

abmv
Thanks abmv. Although this doesn't answer my question I will look into the Data Virtualization link you provided. I voted up your answer.
Gustavo Cavalcanti
+1  A: 

It really seems to be memory leaking. Probably, some of the UI elements in the DataTemplate keep references to other objects that should stay alive even when the UI element is destroyed.

There could be some memory leaks with Image control. Try removing it from the template and see the result. Also, are you subscribing to any events in controls' Loaded events or something like that?

Just some guesses though... As people already said here you might really want to look at your app with performance and memory profilers.

arconaut
A: 

One thing that helped me a lot was to use a class wrapping the Stream class. This is explained in detail here and sure enough I saved a lot of memory by using this method. WPF really keeps the reference to the underlying byte[] and stream for each picture.

Gustavo Cavalcanti