2

I need to reduce the memory leak in c# WPF after disposing all the used objects. But I couldn't reduce the memory consumption completely by using the following code snippet.

Here is my code:

string str;
Uri uri;
private void Button_Click(object sender, RoutedEventArgs e) // "Load" Button
{
    if(img.Source!=null)
    Unload();    
    str = "F://Photos//Parthi//IMG_20141128_172826244.jpg";   // File Size: 0.643 MB            
    uri = new Uri(str);
    img.Source = new BitmapImage(uri);                         
}

private void Button_Click_1(object sender, RoutedEventArgs e) //"Unload Button"
{
    Unload();
}

private void Unload()
{
    Bitmap bmp = GetBitmap(img.Source as BitmapSource);
    bmp.Dispose();
    bmp = null;
    img.Source = null;           
    str = string.Empty;
    uri = null;
}
private Bitmap GetBitmap(BitmapSource source)
{
    Bitmap bmp = new Bitmap(source.PixelWidth, source.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    source.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
    bmp.UnlockBits(data);
    data = null;
    source = null;
    return bmp;
}

After Running the sample, While checking it in Task manager, the following memory consumption reading has produced,

Before "Load" Button is clicked : 10.0 MB

After "Load" Button is clicked : 47.8 MB

After "Unload" Button is clicked : 26.0 MB

After Unloading, I need to reduce the memory closely to 10.0 MB. So please help me regarding this.

Thanks in Advance.

daniele3004
  • 13,072
  • 12
  • 67
  • 75
  • call `GC.Collect()` at the end of `Unload` function – Hamid Pourjam Dec 03 '14 at 06:12
  • `Bitmap` inherits from `Image`, which implements `IDisposable`... why not just take advantage of that and use `using`? By the way, why do you have such a strict requirement that you can't let WPF and .NET take care of the memory for you? I may be wrong, but I feel like C or C++ could be a better choice if you want that level of micromanagement. – B.K. Dec 03 '14 at 06:23
  • 1
    What memory metric are you reading? – leppie Dec 03 '14 at 07:25
  • 2
    keep in mind that depending on how you measure memory usage, you might have more allocated than you would strictly need because the Garbage Collector hasn't gotten to it yet. Explicitly calling GC.Collect() is almost always a bad idea, since it messes with the self-tuning algorithm the Garbage Collector. – Andrew Dec 03 '14 at 07:27
  • 1
    The task manager does not show the 'real' actual memory usage of your application. If you really want to know about your memory usage, use a memory profiler. You can download trial versions. But I can assure you, investing in such a tool is certainly not a waste of money. – Sjips Dec 03 '14 at 07:57
  • When loading the image, the CLR might loads additional assemblies into memory that are required to achieve the required functionality. Check, whether multiple Loads/Unloads actually increase memory usage. – Gene Dec 03 '14 at 07:58

4 Answers4

2

Using the .net platform does not have control over the memory as if it works in c / c ++ The garbage collector operates very complex policies and the fact that you see down the memory to 26 but 10 is normal. The .net reserves a space to recharge faster data and guarantee a free space in main memory without having to require continuous OS.

What I've noticed is perfectly normal. It 'a question that in the past I personally subjected to a Microsoft MVP during a course

View this: http://msdn.microsoft.com/en-us/library/ee787088%28v=vs.110%29.aspx

and this: Best Practice for Forcing Garbage Collection in C#

Community
  • 1
  • 1
daniele3004
  • 13,072
  • 12
  • 67
  • 75
2

First of all, do not use Task Manager to view your memory usage, because it only shows the memory that the windows process allocates. There are plenty of much better tools out there and even the Performance Monitor, which comes on Windows, will give you a better idea of your application performance and any memory leaks. You may start it by running perfmon.exe.

In this sample application, GC does not become aggressive with collections until heap reaches approximately 85MB. And why would I want it to? It's not a lot of memory and it works very well as a caching solution, if I decide to use the same objects again.

enter image description here

So, I suggest taking a look at that tool. It gives a nice overview of what's going on and it's free.

Second of all, just because you called a .Dispose() to release those resources, does not mean that memory is released right away. You're basically making it eligible for the garbage collection and when GC gets to it, it'll take care of it.

The default garbage collection behavior for a WPF application is Concurrent(<4.0)/Background(4.0=<) Workstation GC. It runs on a special thread and most of the time tries to run concurrently to the rest of the application (I say most of the time, because once in a while it'll extremely briefly suspend other threads, so that it may complete its cleanup). It doesn't wait until you're out of memory, but at the same time, it does collection only when it doesn't affect the performance greatly -- sort of a balanced trade-off.

Another factor to consider is that you have a 0.643 MB jpeg file and once you count in BitmapImage, it's a bit more... well, anything above 85,000 bytes is considered to be a large object and thus, it is placed into generation 2, which contains the large object heap. Generation 2 garbage collection is expensive and is done infrequently. However, if you're running .NET 4.5.1, and I'm not sure if you are, you may force a compaction:

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collection();

As with .Dipose(), this is not going happen right away, as it's an expensive process and it'll take a little longer than the generation 1 less-than-a-millisecond sweep. And honestly, you probably wouldn't even benefit from it, since I doubt that you would have a high fragmentation in the LOH with that application. I just mentioned it so that you're aware of that option if you ever need it.

So, why am I giving you a brief lesson on the default GC behavior of a WPF application (and most of .NET applications for that matter)? Well, it's important to understand the behavior of GC and acknowledge its existence. Unlike a C++ application, where you're granted a lot of control and freedom over your memory allocation, a .NET application utilizes a GC. The trade-off is that the memory is freed when it's freed by the GC. There may even be times when it frees it prematurely, from your point of view, and that's when you would explicitly keep an object alive by calling GC.KeepAlive(..). A lot of embedded systems do not make use of a GC and if you want very precise control over your memory, I suggest that you do not either.

If you want to be aware of how memory is being handled in a .NET application, I strongly recommend educating yourself on the inner workings of the garbage collector. What I've told you about is an incredibly brief snapshot of the default behavior and there is a lot more to it. There are a few modes, which provide different behaviors.

B.K.
  • 9,982
  • 10
  • 73
  • 105
0

try to manage the usage of your variables. you can do something like this :

private void Button_Click(object sender, RoutedEventArgs e) 
{
  img.Source = new BitmapImage(new Uri(@"F://Photos//Parthi//IMG_20141128_172826244.jpg"));                         
}

if 'str' and 'uri' is not necessary needed by the whole class you can just add it directly it to your object. Or if you really need to store it and reuse your data that really has a huge amount of size you can just store it on Physical file on a temp file to prevent memory leakage; instead of storing it to memory you can store it on physical storage.

hope it helps

  • 1
    This would allocate an equal amount of memory. As soon as you instantiate an object it allocates memory. It doesn't matter wheter it's inline or not. The scope of that variable is the method. Thus that memory will only be freed after the method ended (And for when a dispose is called on the object when it's a disposable object.) – woutervs Dec 12 '14 at 08:44
0

Your Unload method calls GetBitmap, but GetBitmap returns a new object every time, so as far as I can tell, you're never actually going to dispose of img.Source properly

Joe
  • 1,214
  • 3
  • 15
  • 33