Reputation:
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.
Upvotes: 2
Views: 3601
Reputation: 10172
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.
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.
Upvotes: 2
Reputation: 1214
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
Upvotes: 0
Reputation: 144
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
Upvotes: 0
Reputation: 13960
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#
Upvotes: 2