2

I've got a class that stores an image along with it's filename. I've created an ObservableCollection of this class, and bound that to a WPF listbox. (It's an image viewer of sorts)

I load 50 meg worth of data (currently about 10 images), then I want to remove one, some or all of the images from the observable collection and replace them (so that the memory footprint doesn't get too big while scrolling through many images).

For a start, I've actually got a button on the GUI to load the "next 10 images" - which it does, but it doubles the memory footprint. I've tried calling .Clear() and .ClearItems() from the collection, and also .Remove() and .RemoveAt(n) but the memory doesn't decrease. Am I mistunderstanding how ObservableCollection works?

Here's a synopsis of my code:

public class ImageDataList : ObservableCollection
            {

            public static ImageDataList Load(string path,int startVal, ImageDataList images)
            {
                // Load 10 images from defined start position

                if (startVal<0)
                    startVal=0;

                int endVal = startVal + 10;            
                if (endVal > Directory.GetFiles(path).Length)
                    endVal = Directory.GetFiles(path).Length;

                // Attempt to clear all data from collection
                images.ClearItems();
                images.Clear();
                while (images.Count>1)
                {
                    images.RemoveAt(0);
                }

                for (int i = startVal; i < endVal; i++)
                {
                    string filename = Directory.GetFiles(path)[i];
                    if (filename.Contains(".tif"))
                    {
                        ImageData imgData = ImageData.Load(filename);
                        images.Add(imgData);
                    }
                }
                return images;
            }
        }

After loading the images, it's passed to the GUI via:

listBox.DataContext = images;

I hope I've been clear... let me know if I should add anything!

Edit: For now I seem to have solved the problem by overwriting an item in the ObservableCollection, rather than trying to remove/clear it then add a new one. I still don't understand the memory problem though.

zotty
  • 797
  • 2
  • 9
  • 27
  • 2
    do you dispose of the images that you remove from the collection? – Mitch Wheat Feb 28 '11 at 10:42
  • Do I need to? Inside the Load of the ObservableCollection above, I load the image `ImageData imgData = ImageData.Load(filename);` but I don't explicitly dispose of that. It shouldn't persist, should it? – zotty Feb 28 '11 at 11:17

2 Answers2

3

It may be that the garbage collector hasn't deleted the image objects from memory yet. The reason may be that you have enough memory available on your system so there is no need to delete the objects yet.

Does the memory consumption continue to rise when you load the next 10 images and the next 10 after that?

You should also consider disposing the images as Rakesh Gunijan suggests.

Rune Grimstad
  • 35,612
  • 10
  • 61
  • 76
  • It does keep adding memory for each following set of images - I have 8Gb of ram though, so you may have a point about the garbage collector. – zotty Feb 28 '11 at 11:13
  • You could try to set the MaxWorkingSet for your application to limit how much ram it can allocate. Try to use Process.GetCurrentProcess().MaxWorkingSet – Rune Grimstad Feb 28 '11 at 11:22
  • No, wait! This won't set a memory limit. Check out this SO question for a way to enforce a limit: http://stackoverflow.com/questions/4852062/limiting-process-memory-with-maxworkingset – Rune Grimstad Feb 28 '11 at 11:23
  • Before reading your second comment, I tried loading 2gb worth of data, in 50mb chunks, and there was no evidence of any garbage collection at all. – zotty Feb 28 '11 at 11:38
1

Why dont you create your own view model class like ImageDataViewModel and create observable collection of it instead of inheriting from ObservableCollection.


 public class ImageDataViewModel : INotifyPropertyChanged, IDisposable
    {

        private string _id;
        private string _imagePath;

        public string Id
        {
            get
            {
                return _id;
            }
            set
            {
                _id = value;
                OnPropertyChanged("Id");
            }
        }

        public string ImagePath
        {
            get
            {
                return _imagePath;
            }
            set
            {
                _imagePath = value;
                OnPropertyChanged("ImagePath");
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
            }
        }
        public void Dispose()
        {
          //Do dispose of resources.
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }


    public class YourViewModel : INotifyPropertyChanged, IDisposable
    {
        private ObservableCollection _images;
        public ObservableCollection Images
        {
            get
            {
                return _images;
            }
            set
            {
                _images = value;
                OnPropertyChanged("Images");
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        public void Dispose()
        {
            Images = null;
        }
    }


RockWorld
  • 1,278
  • 2
  • 11
  • 24
  • IMHO, this doesn't help the OP in any way with his memory problem. If you think it does help, please point out, why. – Daniel Hilgarth Feb 28 '11 at 10:58
  • 1
    IMHO, You should create ImageData object in your view not in your view model. This will eliminate disposing of objects, make application lot cleaner. If required implement Converter between string ImagePath property. and UI Image object. – RockWorld Feb 28 '11 at 11:04
  • Wow, it's going to take me a while to decipher what exactly is going on here! Still new to a lot of this. Thanks for the reply, I'll look into it. – zotty Feb 28 '11 at 11:12
  • @Zotty - try to keep application simple as possible. Your ViewModel should not load Image object. Its responsibility of View to load Image object. ViewModel should just maintain path of image (that is string). This will eliminate all memory issues that you are facing. Or to decipher it in simple language, your code is not FIT in terms of WPF programming. – RockWorld Feb 28 '11 at 11:15
  • I assume by "FIT" you mean it doesn't comply with best practice? I think I understand what you mean by removing the image loading to the View - I'll see if I can adjust my program to do that. It may solve some other issues I've been having! I'd not come across View and ViewModel before, I'll go and do some reading. Thanks! – zotty Feb 28 '11 at 11:25