Images in EmguCV not releasing resources - c#

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.

Related

Prevent Memory Bloat When Loading Multiple Images In WPF

I have a very simple WPF app which is used to preview images in any given folder one image at a time. You can think of it as a Windows Image Viewer clone. The app has a PreviewKeyUp event used to load the previous or next image in the folder if the left arrow or right arrow key is pressed.
<Grid>
<Image x:Name="CurrentImage" />
</Grid>
private void Window_PreviewKeyUp(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Left:
DecreaseIndex();
break;
case Key.Right:
IncreaseIndex();
break;
}
var currentFile = GetCurrentFile();
CurrentImage.Source = new BitmapImage(new Uri(currentFile));
}
The problem I'm trying to solve is that there is a large amount of memory bloat when loading multiple images until garbage collection occurs. You can see this in the screenshot I took of the app's memory usage. It's not uncommon for it to exceed 300 MB before garbage collection occurs.
I tried wrapping the image in a using statement, but that doesn't work because BitmapImage doesn't implement IDisposable.
using (var image = new BitmapImage(new Uri(currentFile)))
{
CurrentImage.Source = image;
}
What can I do to prevent memory bloat when loading multiple images into my app?
When you say preview, you probably don't need the full image size. So besides of calling Freeze, you may also set the BitmapImage's DecodePixelWidth or DecodePixelHeight property.
I would also recommend to load the images directly from a FileStream instead of an Uri. Note that the online doc of the UriCachePolicy says that it is
... a value that represents the caching policy for images that come from an HTTP source.
so it might not work with local file Uris.
To be on the safe side, you could do this:
var image = new BitmapImage();
using (var stream = new FileStream(currentFile, FileMode.Open, FileAccess.Read))
{
image.BeginInit();
image.DecodePixelWidth = 100;
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
image.Freeze();
CurrentImage.Source = image;
Call .Freeze() on the bitmap object, this sets it in to a read-only state and releases some of the handles on it that prevents it from getting GC'ed.
Another thing you can do is you can tell the BitmapImage to bypass caching, the memory you see building up could be from the cache.
CurrentImage.Source = new BitmapImage(new Uri(currentFile),
new RequestCachePolicy(RequestCacheLevel.BypassCache));
Lastly, if there is not a lot of programs running on the computer putting memory pressure on the system .net is allowed to wait as long as it wants for a GC. Doing a GC is slow and lowers performance during the GC, if a GC is not necessary because no one is requesting the ram then it does not do a GC.

Image Dispose not working

I have the following code:
private void picturebox_Paint(object sender, PaintEventArgs e)
{
System.Drawing.Image tmp = img[selected].RenderImage(0); //This creates an Image object
e.Graphics.Clear(System.Drawing.Color.Black);
e.Graphics.DrawImage(tmp, movingPoint.X, movingPoint.Y, 512, 512);
tmp.Dispose();
}
This triggers when the user press PageDown, it basically displays the next image in list.
Now, I see my application memory going up and up and barely decreasing in regular intervals.
Am I disposing the tmp Image correctly? I think that's what is causing my memory issues.
Thanks.
Try:
tmp = nothing (or null - my VB and c# gets confused)
or
gc.collect()
which will force it to clear.

GDI throws OutOfMemoryException on loading or cloning bitmap while in an Thread Pool

I have a problem where loading or cloning an png file to an .Net (3.5) Bitmap class causes an OutOfMemoryException within the GDI framework.
This code on run inside an ThreadPool.QueueUserWorkItem, at any time the code creates up to 20 calls to the image loading method that has this code.
// The GDI may throw an OutOfMemoryException on either load or clone of an bitmap
using (var bmp = new Bitmap(filename))
{
var clone = bmp.Clone(new Rectangle(new Point(0, 0), bmp.Size), PixelFormat.Format32bppPArgb);
//post clone bitmap to main thread
}
The solution is to put and try catch around the using statement
try {
using (var bmp = new Bitmap(filename))
{ ... }
}
catch (OutOfMemoryException) { // Swallow the exception}
I have tested and shown this defect on Win7 32&64bit machines and Win8 in Normal and safe modes. This defect only shows on 5 out of 8 machines where the tests where carried out.
Machines are high end Dell and Asus workstations and laptops with different video cards.
Due to the exception coming from the GDI software stack, I don't believe this defect is related to hardware.
The exception may be thrown less than 0.1% of the time, so rare and random. The files are in good order and are not the cause of the problem.
I am looking for an explanation as to why the GDI throws this exception, so I can explain it to my software team and our customer.

Trying to load 150+ grayscale 4096 x 4096 bitmaps. Need help getting around the 2GB limit, I think

Solved: I assumed, incorrectly, that Visual Studio 2012 defaulted to building 64-bit apps when making new projects. Under Solution Properties, Build tab, there is a checkbox marked, "Prefer 32-bit". When I unchecked this checkbox and rebuilt my solution, I was able to load and process over 200 bitmaps at a time. Thanks to Mike Trusov for so politely pointing out the solution to me.
Original question: I've run into a small problem. I have more than 150 grayscale bitmaps that I want to load into RAM on an 8 GB system, but I can't seem to get past 50 or so without throwing an exception. I've tried loading the bitmaps into an array, which is a lost cause, of course, because .NET has a 2GB limit. But it failed long before 2GB worth of bitmaps were loaded. So I tried loading them into a List<List<Bitmap>>, but even that fails at about the same place. At the moment of the exception, Task Manager says I have 3939 MB of Available RAM waiting to be filled. Very strange.
I don't need these bitmaps to be contiguous in RAM. They can be a scattered bunch of 16 MB allocations for all I care. I just want to be able to fill available RAM with a bunch of bitmaps. That's all.
The exception has at various times been an OutOfMemory exception or an ArgumentException, depending on how much available RAM I had when I started the program. In either case, the stack trace dies inside System.Drawing.Bitmap..ctor(String filename). There is nothing wrong with the specific file being loaded at the time of the exception. In fact, when I have it load a different (or even overlapping) set of bitmaps, the error occurs at the same iteration.
Does anyone have a clue they can lend me on how to do this? Am I running into the .NET 2GB limit in some strange way?
To respond to a few questions and comments: I'm using Visual Studio 2012, .NET 4.5, 64-bit Windows 7, on a computer with 8 GB of RAM. Yes, I need all those bitmaps in RAM at the same time for a variety of reasons (performance, image processing reasons, etc). I have pondered using gcAllowVeryLargeObjects, but I don't need or want all my bitmaps in a long chunk of contiguous memory. I would much rather each Bitmap used its own separate memory allocation. Besides, if I had a machine with 64 GB of RAM, it would be absurd to be limited to even 150 Bitmaps of that size. Why won't these bitmaps load without throwing an OutOfMemoryException?
To me, it seems that .NET is trying to keep all Bitmaps in a single 2 GB region. If there was a way to get each Bitmap to (saying more than I know here) have its own separate address space, that might solve the problem. To invoke the language of the long ago days of MS-DOS, I want to allocate and access far memory using a long pointer, not have all my data stuck in a single near segment.
Here is the array code:
List<String> imageFiles; // List of .bmp filenames.
Bitmap[] bmps = new Bitmap[100]; // Stores/accesses the Bitmaps.
private void goButton_Click(object sender, EventArgs e)
{
int i;
// Load the bitmaps
if (bmps[0] == null)
{
// Load the list of bitmap files.
imageFiles = Directory.EnumerateFiles(#"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();
// Read bitmap files
for (i = 0; i < bmps.Length; ++i)
{
bmps[i] = new Bitmap(imageFiles[i]); // <-- Exception occurs here when i == 52 or so.
}
}
}
Here is the List> code:
List<String> imageFiles; // List of .bmp filenames.
List<List<Bitmap>> bmps = new List<List<Bitmap>>(100); // Stores/accesses the Bitmaps.
private void goButton_Click(object sender, EventArgs e)
{
int i;
// Load the bitmaps
if (bmps.Count == 0)
{
// Load the list of bitmap files.
imageFiles = Directory.EnumerateFiles(#"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();
// Read bitmap files
for (i = 0; i < 100; ++i)
{
// Load the bitmap into temporary Bitmap b.
Bitmap b = new Bitmap(imageFiles[i]); // <-- Exception occurs here when i == 52 or so.
// Create and add a List<Bitmap> that will receive the clone of Bitmap b.
bmps.Add(new List<Bitmap>(1));
// Clone Bitmap b and add that cloned Bitmap to the Bitmap of List<Bitmap>.
bmps[i].Add((Bitmap)b.Clone());
// Dispose Bitmap b.
b.Dispose();
}
}
}
There should be no issues loading more than 2gb of bitmaps into memory in a 64bit app (check project settings - might have to create a new configuration for Any CPU based on x86) running on 64bit OS (I'm guessing you are). Also a simple list should work:
var imageFiles = Directory.EnumerateFiles(#"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();
var lst = new List<Bitmap>();
foreach (var imageFile in imageFiles)
{
lst.Add(new Bitmap(imageFile));
}
Do they ALL have to be loaded at the same time? Could you load say, 20 of them, then while you are processing or displaying those, you have a background thread prep the next 20.

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