Memory leak in RenderTargetBitmap - c#

I'm using a RenderTargetBitmap to render a set of controls in order to generate a PDF. The following code segment is the relevant section:
public Drawing.Image RenderPageBitmap()
{
RenderTargetBitmap bit = null;
Drawing.Bitmap bmp = null;
try
{
bit = new RenderTargetBitmap(ImageSource.PixelWidth, ImageSource.PixelHeight, 96, 96, PixelFormats.Pbgra32);
var viewBox = GetPageXaml(); //This method loads some prebuilt XAML from an embedded resource, setting the DataContext as needed.
var siz = new Size(bit.PixelWidth, bit.PixelHeight);
viewBox.Measure(siz);
viewBox.Arrange(new Rect(siz));
viewBox.UpdateLayout();
var draw = new DrawingVisual();
using (var graph = draw.RenderOpen())
graph.DrawRectangle(new BitmapCacheBrush(viewBox), null, new Rect(siz));
bit.Render(draw);
bit.Freeze();
bmp = new Drawing.Bitmap(bit.PixelWidth, bit.PixelHeight, Imaging.PixelFormat.Format32bppPArgb);
var data = bmp.LockBits(new Drawing.Rectangle(Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, Imaging.PixelFormat.Format32bppPArgb);
{
bit.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
}
bmp.UnlockBits(data);
return bmp;
}
catch (Exception)
{
bmp?.Dispose();
throw;
}
finally
{
bit?.Clear();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
Even following other answers on StackOverflow and other forums (like clearing the bitmap and performing a garbage collection) doesn't seem to solve the issue. Each loop of this code can leak ~100MB of memory, which means I quickly hit the ~2GB limit of 32-bit processes.
The leak seems to occur on the RenderTargetBitmap.Render method exclusively, even the DrawingContext.DrawRectangle call doesn't noticeably increase memory usage.
Is there anything I can do to solve this problem?
Here's a snapshot of the memory usage as viewed through JetBrains' dotMemory. Clearly, the .Net heap is correctly cleared, but the unmanaged memory continues to grow.

You return the Bitmap to somewhere. Make sure you Dispose the Bitmap instance once you are done with it. What you are doing in the finally is useless when there is memory leak. If there are references GC wouldn't collect it.
Each loop of this code can leak ~100MB of memory, which means I
quickly hit the ~2GB limit of 32-bit processes.
Are you assuming there is a memory leak? May be there is no memory leak. I would get a good memory profiling tool and test this.
I have used ANTS Memory profiler and I find it good (it comes with 14 days trial). Just execute your logic a few times and see the Instance List if anything is growing. If so, look at the Retention graph to see what holds onto it. That will tell you what exactly happening. Root causes for memory leaks are quite difficult to guess sometimes, fortunately there are good tools for that.

Remove bit.Freeze();. Garbage collection does not collect frozen objects.

Related

C# BitmapImage source memory issues when updating source [duplicate]

I am loading and unloading images in Canvas. I used the below code to load the Image.
Before loading my Image the memory consumption is 14.8MB.
Canvas c = new Canvas();
Image im = new Image();
ImageSource src = new BitmapImage(new Uri(#"E:Capture.png"));
im.Source = src;
im.Height = 800;
im.Width = 800;
c.Children.Add(im);
homegrid.Children.Add(c); //homegrid is my grid's name
The Image displayed correctly and the memory consumption now is 20.8MB. Then I unloaded the Image by the below code:
foreach (UIElement element in homegrid.Children)
{
if (element is Canvas)
{
Canvas page = element as Canvas;
if (page.Children.Count > 0)
{
for (int i = page.Children.Count - 1; i >= 0; i--)
{
if (page.Children[i] is Image)
(page.Children[i] as Image).Source = null;
page.Children.RemoveAt(i);
}
}
page.Children.Clear();
page = null;
}
}
homegrid.Children.RemoveAt(2);
InvalidateVisual();
The Image gets removed after this, but the memory is still 20.8 MB.
Can anyone help me out this?
First of all you should test by explicitly invoking GC.Collect() to collect memory and see that memory releases or not because GC collection is indeterministic. You can't be sure that after your method execution GC runs and reclaim the memory.
So , at end put this code to explicitly force GC to run to check if actually memory is released or not:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
However, there is some known memory leak issues in BitmapImage creation which you can refer here, here and here.
Actually under the covers WPF keeps a strong reference between the static BitmapImage and the Image and hook some events on Bitmap image. So, you should freeze the bitmapImage before assigning to image. WPF doesn't hook events on freezed bitmapImage. Also set CacheOption to avoid any caching memory leak of bitmapImage.
Image im = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(#"E:Capture.png");
bi.EndInit();
bi.Freeze();
ImageSource src = bi;
im.Source = src;
im.Height = 800;
im.Width = 800;
In .Net there is something called the garbage collector (GC) that is in charge of managing the memory you're using.
When you create an instance of an object, it requires some more memory.
When you remove your ImageSource from the Children collection, you don't actually free any memory, you just say "I don't want to use this instance anymore".
At this point the GC will help you. It'll automatically detect instances that are not used anymore, and will free the associated memory for you.
Do note it's an automatic process and you shouldn't (and you don't want to) take care of the memory management.
You can call GC.Collect(); to force the garbage collector to do its job right now, you'll see the memory will be released. NOTE: GC.Collect(); should be used in debug to detect memory leaks, but 99% of times you shouldn't call it explicitly in production code. GC.Collect(); is an operation that can use a lot of CPU time.

Images in EmguCV not releasing resources

I am using EmguCV 3.1.0.2282 and I found that when I use an image, there are times when it doesn't release its resources and eats up memory until the PC is out of resources and an out of memory exception is thrown.
Here is a test code I did within my application. When the button is clicked, a new local image is instantiated based on an existing bitmap in memory. It will do a manual dispose if the checkbox is checked.
private void button1_Click(object sender, EventArgs e)
{
Image<Bgr, Byte> TempImage = new Image<Bgr, Byte>(CurrentLeftBitmap);
TempImage.ThresholdBinary(new Bgr(2.2, 3.3, 4.4), new Bgr(100.0, 100.0, 100.0));
if (checkBox1.Checked)
{
TempImage.Dispose();
TempImage = null;
}
}
I found each time I click on the button, memory goes down and won't be released without an application restart. Even when I do a manual dispose, memory still goes down. Funny thing is that if I commented out the ThresholdBinary step, it works fine. However, it still requires a manual dispose. I've also tried the USING statement but still the same.
My question is that has anyone encounter something similar? What is the proper way of implementing these image objects?
Yes, doing this will run you out of memory. I managed to drain my 32GB system doing 5000 iterations of your method. The problem is ThresholdBinary return another Image, you are not taking that image so the memory gets allocated but has no way to be disposed of. Change
TempImage.ThresholdBinary(new Bgr(2.2, 3.3, 4.4), new Bgr(100.0, 100.0, 100.0));
To
Image<Bgr, byte> newImage = TempImage.ThresholdBinary(new Bgr(2.2, 3.3, 4.4), new Bgr(100.0, 100.0, 100.0));
Will help.
Because they are locals the GC will eventually get around to cleaning them up. But it is always a good idea to dispose of things. So I added
TempImage.Dispose();
newImage.Dispose();
Running this 5,000 time my memory usage hardly moved.

MonoTouch native resource management

Example:
var image = UIImage.FromFile("/path/to/image.png");
var imageView = new UIImageView();
imageView.Image = image;
image.Dispose();
Will the native reference from the UIImageView keep the underlying native image alive or will this crash sooner or later because the native image is actually dead?
Update:
void Foo()
{
var image = UIImage.FromFile("/path/to/image.png");
this.imageView = new UIImageView();
this.imageView.Image = image;
}
Will this leak the underlying native image?
The native UIImageView will keep a reference to the image, so it won't crash.
No, it will not leak the underlying native image. But it might end up freed a lot later than you'd expect. We recommend you call Dispose once you're done with images, since they tend to use a lot of memory which the garbage collector doesn't know about.

C# "Out Of Memory Exception" on returning variable accessor

I am getting an Out Of Memory Exception when I attempt to new a Bitmap and return it through a "get" accessor. The Bitmap is of size 640x480 with depth Int32.
My suspicion is that the C# Garbage Collector is unable to delete these old Bitmaps because they are being returned in the accessor to my variable. I have well over 2GB available so I wouldn't imagine that this "small" image is taking up too much memory. Unfortunately I HAVE to new the Bitmap due to thread locking issues (Trouble with locking an image between threads) The code is as follows:
public Bitmap LiveFrame { get { return GetFrame(500); } }
.....
private Bitmap GetFrame(int timeout)
{
Bitmap ret = null;
//CLEyeCameraGetFrame places image data into this._PrivateBitmap
bool success = CLEyeCameraGetFrame(_Camera, _PtrBmpPixels, timeout);
if(success)
ret = new Bitmap(this._PrivateBitmap);
return ret;
}
Note on unmanaged code:
CLEyeCameraGetFrame is in an unmanaged DLL. I allocate _PtrBmpPixels using Marshal.AllocHGlobal earlier in the code and don't touch it until freeing when closing the app. _PtrBmpPixels was used in the creation of the Bitmap _PrivateBitmap through its constructor that accepts the IntPtr argument "scan0". Thus, whenever _PtrBmpPixels is updated via CLEyeCameraGetFrame, _PrivateBitmap is also updated.
I attempted to fix this by Disposing the PcitureBox Bitmap before reusing it, but that broke the PictureBox display. I have two threads updating two different PictureBox/ImageBoxes:
lock (_CameraLocker)
{
if (_VideoPlaying)
{
try{
if (pbLiveFeed.Image != null)
pbLiveFeed.Image.Dispose();
pbLiveFeed.Image = _Camera.LiveFrame;
pbLiveFeed.Invalidate();
}catch (Exception ex) { }
}
....
lock (_CameraLocker)
{
try{
if (ibProcessed.Image != null)
ibProcessed.Image.Dispose();
procImage = new Image<Bgra, Int32>(_Camera.LiveFrame);
procImage.Draw(new Rectangle(10, 20, 20, 15), new Bgra(1.0, 1.0, 1.0, 1.0), 5);
ibProcessed.Image = procImage;
}catch (Exception ex) { }
}
Could Garbage collection be the cause of this? Is it not safe to return a newed object from a get accessor?
The only real clue in your question is in what is missing. You never said "and I make sure to dispose the bitmap after using it". Which is something you can overlook easily in .NET programming but will come to byte you when you use bitmaps.
The Bitmap class is a very small wrapper class around an unmanaged resource created by GDI+. The actual bitmap pixels are stored in unmanaged memory. Which is why the class has a Dispose() method, that releases the unmanaged memory allocation. The garbage collector can do little to help you get this memory released automatically, a Bitmap object is too small to induce a garbage collection often enough to keep up with the rate at which your program consumes unmanaged memory. An oom-kaboom is the outcome.
You'll need to look at the rest of your code and see how the LiveFrame property is getting used. And make sure that the returned bitmap is getting disposed. If, say, you assign it to a PictureBox.Image property then you have to dispose the old image before assigning it.

Is passing System.Drawing.Bitmap across class libraries unreliable?

I have a 3rd party dll which generates a Bitmap and send back its reference. If I generate a System.Windows.Media.Imaging.BitmapSource out of it immediately then all goes well. But if I save the reference and later on (after a few seconds and many function calls) I try to generate the Bitmapsource, I get
System.AccessViolationException was
unhandled by user code
Message=Attempted to read or write
protected memory. This is often an
indication that other memory is
corrupt. Source="System.Drawing"
when doing :
System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
Any clues on whats going wrong here ? Any pointers will be useful. Thanks.
I think this indicates that the handle (reference to a resource managed by the operating system, rather than .Net) returned by bmp.GetHBitmap is no longer valid - possibly a Dispose has been called somewhere or something like that (not necessarily by your code though).
I'd recommend using another way of persisting the bitmap data that does not rely on handles - possibly stream out the binary data of the bitmap itself immediately, and then throw a reference to that around.
I had a big problem with Bitmaps and access violations as well. What I believe to be happening is that certain bitmap constructors leave file handles open when they should not. Thus, the program you are running detects that the files are in use, when they shouldn't be.
I eventually figured out a solution in that I make a copy of the original bitmap and then dispose the original. Here is my code, which preserves the resolution of the original Bitmap:
Bitmap Temp = new Bitmap(inFullPathName);
Bitmap Copy = new Bitmap(Temp.Width, Temp.Height);
Copy.SetResolution(Temp.HorizontalResolution, Temp.VerticalResolution);
using (Graphics g = Graphics.FromImage(Copy))
{
g.DrawImageUnscaled(Temp, 0, 0);
}
Temp.Dispose();
return Copy;
Obviously, for the first line, yours would be Bitmap Temp = MyThirdPartyDLL.GetBitmap(); or something. If you don't care about the resolution it can be simplified to:
Bitmap Temp = MyThirdPartyDLL.GetBitmap();
Bitmap Copy = new Bitmap(Temp, Temp.Width, Temp.Height);
Temp.Dispose();
return Copy;
After making this change, I was able to do all kinds of File I/O, etc, perfectly fine, hope you can do the same.

Categories

Resources