using the Profiler for first Time

Use this forum for questions on how to use .NET Memory Profiler and how to analyse memory usage.
Post Reply
Guest

using the Profiler for first Time

Post by Guest » Tue Aug 30, 2005 3:46 pm

Hi,

I 'm quite new in C# and in .NET framework and stambled on an issue that is beoyond my skills to solve. I m working on an API that records human resources in an organization. In the form that I view the account information I m loading a JPEG image. Looking at the Mem usage of Task Manager I realized that there is some extensive memory usage when I load JPEG files (10,000 dpi). So I downloaded a trial version of the MemProfiler to try and see what's going on?

Now the problem is when the image is loaded the API mem usage is boosted to 13 MB plus. So far I don't understand why a pic of 200 KB is taking 13 MB of memmory. OK I can live with this mem usage. But when I go to the next pic another 13 MB is loaded and this goes on till 214 MB of mem usage till the progroma is reset to the initial mem usage.

I would think the issue has to do with the garbage collector and the Image Object.

The Image is loaded from the method
photoImage = new Bitmap(String.Concat(Application.StartupPath.ToString(), "/Photos/", aadTextBox.Text, ".jpg"));
photoPictureBox.Image = photoImage;

My first question is that I get different values in the Task Manager and in MemProfiler. I get every time I load the image 13 MB extra on mem usage and in MemProfiler I get Total Heap 1,3 MB. How is that possible?

Second is there a way to see the actual name of my instances for example I can see in System.Drawing.Image.Bitmap but not the name I use in my code. That's kind of confusing? I can trace to the pictureObject but I m not sure!

Last question is how can I solve the problem with the Memory Leak of the Images and how can MemProfiler can help me? I m sure what it happens is it's loading images without disposing and creating the mem leak. But it should at least dispose all the images when the FORM is closed.

Anyway thanks
Dimi

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Tue Aug 30, 2005 9:25 pm

I don't know how big your bitmap is, but a large bitmap can consume 13 MB of memory. But this memory will not be presented by the profiler, since the profiler only presents managed memory usage. An instance of the Bitmap class only occupies 20 bytes of managed memory, but it contains a handle to all the bitmap data.
Since the garbage collector only looks at the managed memory, it has no notion of the real cost of the Bitmap and therefore the bitmap MUST be disposed when not needed anymore.

When you dispose a Form, all child controls and components of the form will also be disposed, but the Image of the PictureBox will not be disposed. The reason for this is that you should not dispose an instance which you don't own. The image in the PictureBox may be used in more than one place (e.g. another PictureBox on another form). So, since you're the one that creates the Bitmap, you're also the one responsible for disposing it.

Your code should look something like:

Code: Select all

if( photoImage != null )
{
  photoPictureBox.Image = null; // Avoid having a disposed Bitmap assigned (not really necessary)
  photoImage.Dispose();
}
photoImage = new Bitmap(String.Concat(Application.StartupPath.ToString(), "/Photos/", aadTextBox.Text, ".jpg")); 
photoPictureBox.Image = photoImage; 

...

protected override void Dispose( bool disposing )
{
  base.Dispose( disposing );
  if( disposing )
  {
    if( photoImage != null )
    {
      photoImage.Dispose();
      photoImage = null; // Not really necessary, but you prevent using it after it's disposed
    }
    // Rest of dispose code
  }
}
Second question: To be correct, an instance does not have a name, only the fields or variables that reference the instance. And it is possible to find out the name of a field that references an instance, as long as instance data has been collected. If you look at the instance details of your Bitmap, and select the "References" tab, then you should be able to see all other instances that have a reference to your Bitmap. Double-clicking one of them will bring up the instance details of the instance with the reference. Now select the "Field values" tab. If instance data has been collected, then you should be able to locate the field that contains a reference to your bitmap. (In future versions of the profiler we will present the field name under the "References" tab, if we can identify it.)


Third question: You don't actually have a memory leak. When the garbage collector notices that your Bitmap instance is no longer reachable(which it will do eventually), it will queue it up for finalization. When the finalizer runs, all bitmap data will be released and the managed memory will be eligible for GC. However, your program suffers from very bad unmanaged memory utilization. I suggest that you use the dispose tracker of the memory profiler, to make sure that you dispose all instances correctly (especially Bitmaps)
Best regards,

Andreas Suurkuusk
SciTech Software AB

Guest

Post by Guest » Wed Aug 31, 2005 9:30 am

Hi,

Thanks for the quick answer and all the details. It made things much more clear to me.

The bitmap is consuming a lot of memory because I m using bitmaps optimized for prinitng (10,000 dpi). To solve the problem I cam up with a similar code because I relate it with a previous and next button and the bitmap which is saved in the folder Photo:

Code: Select all

			FileInfo filePhoto = new FileInfo(String.Concat(Application.StartupPath.ToString(), "/Photos/", aadTextBox.Text, ".jpg"));
			if (filePhoto.Exists)
			{
				if (photoPictureBox.Image == null)
				{
					photoImage = new Bitmap(String.Concat(Application.StartupPath.ToString(), "/Photos/", aadTextBox.Text, ".jpg"));
					photoPictureBox.Image = photoImage;
				}
				else
				{
					photoImage.Dispose();
					photoImage = new Bitmap(String.Concat(Application.StartupPath.ToString(), "/Photos/", aadTextBox.Text, ".jpg"));
					photoPictureBox.Image = photoImage;
				}
			}
			else
			{
				photoImage.Dispose();
				photoPictureBox.Image = null;
			}
On second and three you're right.

I got 2 more questions :
1) Does MemProfiler work on unmanaged code? I don't see any reason it should not. I m asking this because I m working on Unmanaged DirectX and OpenGL! How helpful memProfiler will be on that ase?
2)I see on my program a lot of undisposed System.Drawing FontFamily, Font and System.Windows.Forms PaintEventArgs. How is that possible? Since all these instances should be managed through the GC and I never use any call on these methods?

I found the MemProfiler very useful to identify a lot of things about the memory usage of my API. I quite new in managed programming (more experienced in Unmanaged).

Thanks in advance for all the great help
Dimi

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Wed Aug 31, 2005 3:10 pm

Hi,

Your code will dispose the bitmaps correctly, but it seems a bit risky to dispose the photoImage without checking for null (when filePhoto.Exists is false).

The current version of the profiler does not track unmanaged resources and unmanaged memory. This is something we are working on implementing, and an unmanaged resources tracker will be included in a future version.

The framework itself fails to dispose several instances, e.g. instances of PaintEventArgs. Unfortunately, there's not much to do about it, since these instances are created and owned by the framework. However, failing to dispose instances of the classes you mention will not have a very big performance impact, since the unmanaged resources they wrap are not very big or scarce (but they have to be finalized, which adds a performance and memory overhead).
Best regards,

Andreas Suurkuusk
SciTech Software AB

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 20 guests