I'm looking for a way to process many images, but not run out of memory. When my app first runs it has to create a number of thumbnails and store them locally. This only happens one time.
I'm getting out of memory errors though.
Roughly I am going this:
[Loop BigPaths]
sourceImg = UIImage.FromFile (nextBigpath);
img = UIImageTools.MakeSquare (sourceImg, 50,3);
img.AsJPEG ().Save (path, NSDataWritingOptions.Atomic, out err);
sourceImg.Dispose ();
sourceImg = null;
img.Dispose ();
img = null;
[end loop]
UPDATE:
To fix it, I am now calling GC.Collect() after every 10 items, waiting 50 milliseconds in a Thread.Sleep().
I also made sourceImg img defined outside the loop.
With these 2 changes, I am no longer getting memory errors.
This is the solution I found worked.
Create the image variables outside the loop and reuse them, making sure that after each use .Dispose() is called.
After 50 images call GC.Collect() then Thread.Sleep(50) to give the GC time to clean up.
After that there were no memory issues.
Related
How do you dispose of bitmaps and images when in a for...next loop?
Particularly image(of bgr, byte) images.
The "image(of bgr, byte)" images are from the emgu library.
The Dispose() command works fine when you dispose of a single bitmap or image.
But when you are looping through multiple images, Outofmemory errors occur.
Even when applying the using ... end using commands, memory issues occur.
For example, this will throw memory errors for me:
Dim pic As Bitmap = New Bitmap(270, 100)
For i = 0 to 100
Dim CleanImage As New Image(Of Bgr, Byte)(pic)
'this command comes from the emgu library - tesseract
OCRz.Recognize(CleanImage)
CleanImage.Dispose()
Next
As will:
Dim pic As Bitmap = New Bitmap(270, 100)
For i = 0 to 100
Using CleanImage As New Image(Of Bgr, Byte)(pic)
OCRz.Recognize(CleanImage)
End Using
Next
I've tried GC.Collect(). This didn't work.
How do I properly rid the program of these annoying bitmaps and images?
I'm desperate for a solution.
The emgu wiki states the following:
Automatic Garbage Collection The Image class
automatically take care of the memory management and garbage
collection.
Once the garbage collector decided that there is no more reference to
the Image object, it will call the Disposed method,
which release the unmanaged IplImage structure.
The time of when garbage collector decides to dispose the image is not
guaranteed. When working with large image, it is recommend to call the
Dispose() method to explicitly release the object. Alternatively, use
the using keyword in C# to limit the scope of the image
using (Image<Gray, Single> image = new Image<Gray, Single>(1000, 800))
{
... //do something here in the image
} //The image will be disposed here and memory freed
This is exactly what I am doing. Yet, I receive this OutOfMemory exception. What is going on?
I launch the IShellItemImageFactory::GetImage method for each item in a folder in a number of background threads. The code looks like that:
HRESULT GetImage(IShellItemImageFactory* pImgFactory,
SIZE Size, COLORREF BkColor, HBITMAP *phbm)
{
if (pImgFactory == 0 || phbm == 0)
return E_POINTER;
*phbm = 0;
HBITMAP hBmp = 0;
HRESULT hr = pImgFactory->GetImage(Size, SIIGBF_BIGGERSIZEOK, &hBmp);
if (SUCCEEDED(hr) && hBmp)
{
*phbm = CPicture::StretchBitmap(hBmp, Size, BkColor);
}
return hr;
}
Sometimes I have the all 16 threads stuck inside call to pImgFactory->GetImage for different items. They all stuck in one and the same place, which could be seen in the provided stack. I checked that different threads process different items. What can be a cause of such strange phenomenon?
EDIT:
After David Heffernan's response I realized that the IShellItemImageFactory interface itself can be not thread safe. Our threading subsystem automatically initializes each thread as STA (by the call to CoInitialize(0) function). But may be, for IShellItemImageFactory I need MTA threads. Is there a way to discover the IShellItemImageFactory's coclass CLSID, in order to find in the Registry its threading requirements?
EDIT2:
Probably, our threading mechanism somehow related to the problem. In this specific case we use an engine that we call "Job Queue". It is non-blocking FIFO queue, which elements describe a job. The description contains pointers to job's algorithm and job's data. Typically (but not necessary) the main thread puts jobs to the queue. A free thread from thread pool may get element from the queue and perform the job. This mechanism worked well for us already a couple of years. But may be, it somehow affects icon extraction. May be, I wasn't sufficiently exact in defining the icon extracting algorithm and data. I don't know how can I determine it.
The phenomenon is not really a deadlock. It happens when extracting images of subfolders in a folder, which was not still cached by the Windows. Suppose there is a folder F with 20 subfolders F1,F2,...,F20, each of which contains 20+ other subfolders and files. If folder F is not cached, extraction of 20 images of its subfolders may take 15 - 25 min (on my Win10 8-core computer). After the all images were once extracted, repeated requests for images in that folder F are performed fast.
Dear programmers, i wrote a program wich target a Windows Mobile platform (NetCF 3.5).
My programm has a method of answers check and this method show dynamically created pictureboxes, textboxes and images in new form. Here is a method logic:
private void ShowAnswer()
{
PictureBox = new PictureBox();
PictureBox.BackColor = Color.Red;
PictureBox.Location = new Point(x,y);
PictureBox.Name = "Name";
PictureBox.Size = Size(w,h);
PictureBox.Image = new Bitmap(\\Image01.jpg);
}
My problem is in memory leaks or something. If the user work with a programm aproximately 30 minutes and run the ShowAnswer() method several times, Out of memry exception appears. I know that the reason may be in memory allocation of bitmaps, but i even handle the ShowAnswers form closing event and manually trying to release all controls resources and force a garbage collector:
foreach(Control cntrl in this.Controls)
{
cntrl.Dispose();
GC.Collect();
}
It seems like everything collects and disposes well, every time i check the taskmanager on my windows mobile device during the programm tests and see that memory were released and child form was closed properly, but in every ShowAnswer() method call and close i see a different memory amount in device taskmanager (somtimes it usues 7.5 Mb, sometimes 11.5, sometimes 9.5) any time its different, but it seems like sometimes when the method start to run as usual memory is not allocated and Out of memory exception appears.. Please advice me how to solve my problem.. Maybe i should use another Dispose methods, or i should set bitmap another way.. thank you in advance!!!
Depending on how you're handling the form generation, you might need to dispose of the old Image before loading a new one.
private void ShowAnswer()
{
PictureBox = new PictureBox();
PictureBox.BackColor = Color.Red;
PictureBox.Location = new Point(x,y);
PictureBox.Name = "Name";
PictureBox.Size = Size(w,h);
if(PictureBox.Image != null) //depending on how you construct the form
PictureBox.Image.Dispose();
PictureBox.Image = new Bitmap(\\Image01.jpg);
}
However, you should also check before you load the image that it's not so obscenely large that it munches up all of your device's memory.
Edit: I don't just mean the size of the compressed image in memory - I also mean the physical size of the image (height & width). The Bitmap will create an uncompressed image that will take up much, much more memory than is resident on storage memory (height*width*4). For a more in-depth explanation, check out the following SO question:
OutOfMemoryException loading big image to Bitmap object with the Compact Framework
I have this code in my app:
var newImage = // ...
if (imageView.Image != null && imageView.Image != newImage)
imageView.Image.Dispose ();
imageView.Image = newImage;
I have three related questions:
Does it immediately release the memory occupied by the previous imageView.Image?
If it does, is there a cleaner solution?
Does this have anything to do with NSAutoreleasePool?
Does it immediately release the memory occupied by the previous imageView.Image?
Not immediately but it should be much faster than waiting for the Garbage Collector.
Calling Dispose will drop the managed reference to the native UIImage. If nothing else (natively) has a reference to the UIImage (RetainCount == 0) then it will be freed (ObjC reference counting).
In your code imageView still has a reference to it until its Image property is set to newImage - which is why I answered not immediately.
If it does, is there a cleaner solution?
Not really. Letting the GC do it's work is cleaner looking - but image can be very big and are worth freeing asap.
Also it's not really worth (and would not be cleaner anyway) adding a local variable to make sure (if no other native reference exists) the image will be freed immediately - it will happen on the next line.
Does this have anything to do with NSAutoreleasePool?
Anything ? well it's memory related in both cases.
Creating images will use (cache) the current NSAutoreleasePool and will, eventually, be drained. If you process a lot of stuff (e.g. a loop) then it's often worth having your own, short-lived, pool to ensure a faster drain.
Some API (well know to require a lot of memory) are decorated with an attribute that will automatically add (btouch) an NSAutoreleasePool - but it's not easy to find out which.
In doubt you better use Apple Instruments to measure...
I am pretty sure I am suffering from memory leakage, but I havent 100% nailed down how its happening.
The application Iv'e written downloads 2 images from a url and queues each set of images, called a transaction, into a queue to be popped off by the user interface and displayed. The images are pretty big, averaging about 2.5MB. So as a way of speeding up the user interface and making it more responsive, I pre-load each transaction images into wxImage objects and store them.
When the user pops off another transaction, I feed the preloaded image into a window object that then converts the wxImage into a bitmap and DC blits to the window. The window object is then displayed on a panel.
When the transaction is finished by the user, I destroy the window object (presumably the window goes away, as does the bitmap) and the transaction data structure is overwritten with 'None'.
However, depending on how many images ive preloaded, whether the queue size is set large and its done all at once, or whether I let a small queue size sit over time, it eventually crashes. I really cant let this happen .. :)
Anyone see any obvious logical errors in what im doing? Does python garbage collect? I dont have much experience with having to deal with memory issues.
[edit] here is the code ;) This is the code related to the thread that downloads the images - it is instanced in the main thread the runs the GUI - the download thread's main function is the 'fill_queue' function:
def fill_queue(self):
while True:
if (self.len() < self.maxqueuesize):
try:
trx_data = self.download_transaction_data(self.get_url)
for trx in trx_data:
self.download_transaction_images(trx)
if self.valid_images([trx['image_name_1'], trx['image_name_2']]):
trx = self.pre_load_images(trx)
self.append(trx)
except IOError, error:
print "Received IOError while trying to download transactions or images"
print "Error Received: ", error
except Exception, ex:
print "Caught general exception while trying to download transactions or images"
print "Error Received: ", ex
else:
time.sleep(1)
def download_transaction_images(self, data):
""" Method will download all the available images for the provided transaction """
for(a, b) in data.items():
if (b) and (a == "image_name_1" or a == "image_name_2"):
modified_url = self.images_url + self.path_from_filename(b)
download_url = modified_url + b
local_filepath = self.cache_dir + b
urllib.urlretrieve(download_url, local_filepath)
urllib.urlcleanup()
def download_transaction_data(self, trx_location):
""" Method will download transaction data and return a parsed list of hash structures """
page = urllib.urlopen(trx_location)
data = page.readlines()
page.close()
trx_list = []
trx_data = {}
for line in data:
line = line.rstrip('|!\n')
if re.search('id=', line):
fields = re.split('\|', line)
for jnd in fields:
pairs = jnd.split('=')
trx_data[pairs[0]] = pairs[1]
trx_list.append(trx_data)
return trx_list
def pre_load_images(self, trx):
""" Method will create a wxImage and load it into memory to speed the image display """
path1 = self.cache_dir + trx['image_name_1']
path2 = self.cache_dir + trx['image_name_2']
image1 = wx.Image(path1)
image2 = wx.Image(path2)
trx['loaded_image_1'] = image1
trx['loaded_image_2'] = image2
return trx
def valid_images(self, images):
""" Method verifies that the image path is valid and image is readable """
retval = True
for i in images:
if re.search('jpg', i) or re.search('jpeg', i):
imagepath = self.cache_dir + i
if not os.path.exists(imagepath) or not wx.Image.CanRead(imagepath):
retval = False
else:
retval = False
return retval
Also, I'd like to add that sometimes, just before the crash I get peculiar errors in my console, they look like corrupt image errors but the images are not corrupted, the error has happened at all stages on all images.
Application transferred too few
scanlines [2009-09-08 11:12:03] Error:
JPEG: Couldn't load - file is probably
corrupted. [2009-09-08 11:12:11]
Debug: ....\src\msw\dib.cpp(134):
'CreateDIBSection' fail ed with error
0x00000000 (the operation completed
successfully.).
These errors can happen a la carte, or all together. What I think is happening is that at some point the memory becomes corrupted and anything that happens next, if I load a new transaction, or image, or do a cropping operation - it takes a dive.
So unfortunately after trying out the suggestion of moving the pre-loading function call to wxImage into the main gui thread I am still getting the error - again it will occur after too many images have been loaded into memory or if they sit in memory for too long. Then when I attempt to crop an image the i get a memory error - something is corrupting, whether in the former case I am using too much or dont have enough (which makes no sense because I've increased my paging file size to astronomical proportions) or in the latter case where the length of time is causing a leak or corruption
The only way I think I can go at this point is to use a debugger - are there any easy ways to debug a wxPython application? I would like to see the memory usage in particular.
The main reason why I think I need to preload the images is because if I call wxImage on each image ( I show two at a time) each time i load a 'transaction' the interface from one transaction to the next is very slow and clunky - If I load them in memory its very fast - but then I get my memory error.
Two thoughts:
You do not mention if the downloading is running a separate thread (actually now I see that this is running in a separate thread, I should read more closely). I'm pretty sure that wx.Image is not thread-safe, so if you are instantiating wx.Images in a non-GUI thread, that could lead to trouble like this. (This is almost certainly the issue, most wx classes/objects/functions are not thread-safe).
I've been bitten by nasty IncRef/DecRef bugs in wxPython (due to the underlying C++ bindings) before (mostly associated with wx.Grid and associated classes). While I don't know of any with wx.Image, it wouldn't surprise me to find out you may be required to manually manage memory like you have to in wx.Grid sometimes.
Edit
You need to instantiate the wx.Image in the GUI thread, not the downloading thread (which your above code looks like you are currently instantiating in the non-GUI thread). In general this is almost always going to cause lots of problems in any GUI toolkit. You can search the wxPython mailing list for lots of emails where this is the case. Personally I would do this:
Queue for download urls.
Thread to download images.
Have the downloading thread places a disk location (watch out for race conditions!) in a separate queue and post custom wx.Event(threadsafe) (threadsafe with wx.PostEvent function) to the App thread.
Have the GUI thread pop the file locations and instantiate wx.Image ----> wx.Bitmap (maybe with wx.CallAfter to process when App is idle)
Display (Blit) as needed.