3

I want to add 1000 images (each size is (40 to 100) KB) in a panel at run time in a desktop application. At first user browses all the images and load them on a panel. When it loads images one after another then memory usage shown in the task manager increases rapidly and after a certain number of images it shows the “Out of Memory Exception”. Where is the fault in my code?

Before loading the 700 images task manager shows 1.05 GB memory usage. After loading task manager shows 2.04 GB and 2 GB RAM overflows

int picnumber = 0;
        int numberOfImages = 12;

        numberOfImages = Convert.ToInt32(textBox1.Text.ToString());

        for (int i = 0; i < numberOfImages; i++)
        {
            GroupBox gBox = new GroupBox();

            picnumber++;


            ////////////////////////////////

            // calculate the position of the groupbox where it is placed.
            if ((picnumber % 3) == 1)
            {
                x = initX;
            }
            else
            {
                if ((picnumber % 3) == 0)
                {
                    x = initX + 2 * (130 + 20);
                }
                else
                {
                    x = initX + 130 + 20;
                }

            }
            ///////////////////////////////////


            System.Drawing.Point CurrentPoint;

            CurrentPoint = panel1.AutoScrollPosition;
            y = initY + ((picnumber - 1) / 3) * (130 + 20) - (Math.Abs(panel1.AutoScrollPosition.Y));

            gBox.Text = picnumber.ToString();

            //place the groupbox in the appropriate position.
            gBox.Location = new System.Drawing.Point(x, y);
            gBox.Size = new System.Drawing.Size(130, 130);

            Bitmap btmap = new Bitmap(@"E:\43.jpg");
            // attach the image to the groupbox
            gBox.BackgroundImage = btmap;
            **gBox.BackgroundImageLayout = ImageLayout.Stretch;
            // add the groupbox that contains image to the panel.
            panel1.Controls.Add(gBox);**

But I have seen some applications that can load huge number of images and takes memory that is negligible, for example, “Batch Image Resizer”( http://www.jklnsoft.com/)

How does the application handle memory? What mechanism do they follow?

Before loading the 700 images task manager shows 1.05 GB memory usage. After loading task manager shows 1.06 GB

Development environment: C#.net framework 4, windows xp, Visual Studio 2010, RAM: 2 GB

learner
  • 81
  • 1
  • 9

4 Answers4

7

It's important to note that a 100kb JPG will take up a lot more memory than just 100kb. 100KB is the compressed size of the data on the disk. If you have a 32-bit (which means 4 bytes per pixel of image information) image that's 800x600, it might be 100kb on disk, but you decompress it and store it in memory to be able to display it, that's 800 * 600 * 4 = 1,920,000 bytes = 1.83 MB of RAM. 1.83 * 700 = 1,281 MB of RAM used to hold all those images.

The solution is to load the image and create a smaller thumbnail of it in memory, then discard the original image from memory. If your 800x600 has an 80x60@16-bit thumbnail, then that only takes 9.3kb of RAM to display. 700 of those would only consume 6.5MB of RAM - a huge difference!

Chris Heald
  • 61,439
  • 10
  • 123
  • 137
5

You probably want to load them on-demand and cache them. What this means is that if you have, say, 20 photos visible in your window, you might load 40 photos - 10 before the current position, the 20 visible photos, and 10 after the current position. As the user scrolls, you can throw out any that have scrolled past the start position, and read in those that will come into view soon. This way you only ever have a few in memory, and you're only ever reading a few more.

user1118321
  • 25,567
  • 4
  • 55
  • 86
3

You have to dispose of resources like bitmaps after you have used them. You can do this with:

using(Bitmap btmap = new Bitmap("E:\etc...")) {
   ... code here
}

But do this with each iteration, not after you have looped through all your resources!

Digbyswift
  • 10,310
  • 4
  • 38
  • 66
0

Use CacheOption for it.

public static ImageSource BitmapFromUri(Uri source)
{
    var bitmap = new BitmapImage();
    bitmap.BeginInit();
    bitmap.UriSource = source;
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.EndInit();
    return bitmap;
}
Dipitak
  • 97
  • 1
  • 1
  • 3