I have an iPhone application that will save number of images in it.
I used SQLite in-order to save the images into the application.
There were lot of memory issues after i saved more than 20 images.
Do any one know how many images users can save in their app database?.
if it depends on iphone memory, how can we get that max limit?.
One more thing:
I have removed the database and used the file system to store the images into application.
but same problem replicated.
Can any one suggest me on this.
I owe a lot for your great help.
Thanks in advance.
I believe storing the image in the file system is a much better idea, could you provide us with more information, like image size, and also some of your saving code?
When you say 'memory issue', do you mean leaks causing out of memory exceptions or are you sure your database has filled the device's disk completely. To know how much SQLite can store read the discussion on this question.
On the other hand, if you are having out of memory exceptions (didReceiveMemoryWarning) you need to tune your code. Specially, when working with many images, just avoiding the use of 'imageNamed' factory method does the job. This is because it creates an autorelease object which remains longer in the memory. Instead create UIImages using the 'initWithContentsOfFile' to create the image and release it immediately after it is used. If you still face the memory issue, you probably have some leaks and need to post some code for people to answer more correctly.
Related
I search how find my problem.
In my application for iPad when i treat data i have an increase memory and never release that memory, i try instruments leaks memory but that not find memory leaks (i try with profile and analyze).
So my question is they have an other instrument for find memory leaks or other methods?
Thanks in advance for your consideration.
P.S : I don't post code cause that concerned a big part of my code but the part where memory increase is a part where i download from a FTP some zip files (based on SimpleFTPSample from Apple Doc) i unzip this files (with framework minizip) this zip files contains some images and XML files i parse this XML files (around 7200 XML files and 35 000 images files saved) i saved some information (issue of parsing) in data base and that its. If you need part of my code for help me ask me.
Make sure if you have Zombies turned off in Scheme:Diagnostics. With Zombies on no memory is ever deleted. Testing for memory leakage should always be done with Zombies off.
This usually happens when you keep the objects in a datastructure (NSDictionary, NSArray, eg), even after you don't need them anymore. Check with Instruments' Allocations which objects are accumulated, and check in your code where you keep instances of those objects.
Another cause could be long-running threads.
If the loading and parsing you mentioned are done in a single thread that takes a long time, then you may need to do #autoreleasepool in a loop somewhere to force temporary objects to be cleaned up regularly.
It might also be no problem at all. You say you load a lot of images. Images are by default cached by iOS, and only released when necessary to clean up memory. If Instruments "Trace Highlights" shows a lot of memory usage, but "Allocations" doesn't, then this is likely the cause.
I am using a custom UITableViewCell with 3 UIImages in a UITableView with 50-100 rows. Its similar to a UITableViewCell the Facebook iPhone app uses for its news feed view.
The application has 4 similar UITableViews which may be open at the same time via a UITabConroller.
The images are lazy loaded, there is a cache on disk so that no images are loaded twice from the server and there is also a NSMutableDictionary for images allowing in-memory reuse of the same image eg: a users profile picture appears multiple times
This setup is extremely fast but takes a lot of memory even after using the NSMutableDictionary for image reuse.
I tried a variation without the NSMutableDictionary where images are either loaded from the server or pulled from the disk cache every time cellForRowAtIndexPath is called. This setup is extremely memory efficient but causes a noticeable lag in the UITableView scrolling.
A mid-way approach is to free the NSMutableDictionary for images when a low memory warning is received.
Will really appreciate recommendations to optimize memory usage and speed in this scenario and or an insight into how the Facebook iphone app or three20 execute this conceptually.
I have an app that is very similar to yours in many respects (uses Three20, has several tabs across the bottom, each tab can have a table, each cell can have one or two images); and the approach I'm taking is the one you mentioned near the end of your post:
A mid-way approach is to free the NSMutableDictionary for images when a low memory warning is received.
Personally, I quite like iOS's approach to memory management, of warning me when memory is getting tight. The Mac/PC approach of "just use all the memory you want, we'll swap it out to disk if memory gets tight" has the disadvantage that even though the OS is the only one who really knows how much pressure there is on memory, it isn't telling you. I think what every polite app would really like to say (if apps could talk) is, "I'd be happy to use as much memory as you'll give me, but I don't want to be a bother, I don't want to slow down any other apps, so if you could please give me a hint as to how much memory I can use without causing problems, I would appreciate it."
Well that's what iOS's memory warnings give you, in my opinion. So, just keep as many images cached in memory as you want; and when you get a memory warning, empty the in-memory cache. To me it's really the best of both worlds.
Also, you should definitely take a look at Three20's TTURLCache, although I can't tell you a lot about it because I haven't dug into it very much. What I do know is:
If you retrieve your messages via TTURLImageResponse, it will automatically cache them in TTURLCache's image cache.
You can also store and load your own images (and other data) in the TTURLCache.
Three20 seems to take an approach similar to what I am talking about. Take a look at this code from Three20Network/Sources/TTURLCache.m (the NO argument means don't remove from disk, only remove from memory):
- (void)didReceiveMemoryWarning:(void*)object {
// Empty the memory cache when memory is low
[self removeAll:NO];
}
In addition, that class also allows you to set a maximum size for the in-memory cache, but by default there is no maximum size.
you would purge images when they go offscreen, then read the images from the locale cache on demand from a secondary worker thread when needed. since one can zip through tables, add support for read cancellation (esp. for requests which come off the server). NSOperation is a good api for this.
if you know your table's small, then you could opt to avoid purging in such cases.
also, rescaling the image to the size you'll display it as is often a good idea (depending on how far you want to take an optimization). assuming the source is larger than the displayed size: this will reduce memory requirements, drawing speed, disk space, and disk read times.
you can also read three20's sources to see what they have done.
I build a parsing algorithm using NSXMLParser.
Im having doubt as to what is the best strategy for keeping my memory usage on a minimum.
I have a valueObject (e.g. "Person") this object has ≈ 30 NSString properties, while parsing the xml I continually alloc and release a temporary Person object as the nodes are traversed.
I checked this and there is only one of these Person objects instantiated at any time.
When a node is traversed and a Person is "build" I pass the Person to a NSMutableArray and release this Person. Seems no problem there. (I'll need the array for a tableView).
When I reach around 50+ Person objects in the array my app just quits, didReceiveMemoryWarning doesn't get called, no other warnings, no parseErrorOccurred, nothing?
If I limit the number of Persons in xml the app does just fine, I haven't been able to find any memory leaks with Instruments.
I think that I simply can't hold 50+ Person objects in an array… seems a bit harsh, but I haven't got much memory experience with the iPhone, so this is just a guess.
The xml is search results from which the user probably only needs a few, so persisting them to my core model to keep them around for display seems a bit crazy.
What would be a good strategy for keeping these Person objects around? or am I missing a huge memory leak since the iPhone should be able to handle much more than this?
Hope some experienced developers can point me in the right direction:)
Thank you!
Despite NSXMLParser being a SAX-based parser it does not support parsing an input stream, which means that the entire XML string you are parsing is kept in memory. This on its own is a big issue, but as you parse the problem gets worse as you start duplicating the string data from the XML in your Person objects.
If your strings are really big, you've got the second problem of having too many parsed Person objects in memory at one time.
The first problem can be solved by using AQXMLParser from Jim Dovey's AQToolkit library, which provides an NSXMLParser-like API but with support for streaming the data from disk.
The second problem can be solved using a disk-based persistence technology, like Core Data, SQLite Persistent Objects, or even just storing the Person objects on disk yourself.
How long are those strings? Generally, on the iPhone 3G and older models, your app should have a minimum of about 20 MB of memory available (much more on the 3Gs). This is no absolute rule, of course, but a decent rule of thumb. To occupy this much memory with 50 objects would mean ~400-500 KB per Person object. Is this in the ballpark? If so, you will probably need a memory management strategy that does not keep all objects in memory at the same time. Core Data can probably help you a great deal in that case.
If you did not receive a memory warning it is probably not the reason your app is quitting. In Xcode go to the organizer, and select the device, then click on the console tab. If they app was shutdown for memory reasons there will be a system message in the console log saying it is killing the app due to memory pressure.
The answer is to chop up the incoming stream, I wrote a post about it some time ago:
https://lukassen.wordpress.com/2010/01/15/feeding-nsxmlparser-a-stream-of-xml/
Apple just released some sample code on lazy loading images in a UITableView a week ago. I checked it out and implemented it into my own UITableView (which is a drawRect one for fast scrolling), to see if there was a difference from what I was already doing.
After implementing I am not sure what is best; the new code or what I already had. I am not seeing much of a speed improvement on my 3GS.
"Sandbox" method: Load images lazily, then save to local tmp folder in the sandbox. Each time the cell is displayed it looks for whether an image with that filename is already located in the sandbox folder. If it is, it retrieves the image and displays it, if not it continues with the download, saves it locally and then displays it. The benefit with this is that the images won't be blank the second time you open the app. They will already be downloaded and ready for displaying.
Caching method: This also loads the images lazily, however, now I include a UIImage on each object in the array that's displayed in the tableview. Instead of saving the image locally, I now download the image and put it into the array for the object. Now, instead of checking for the filename every single time, it jut check whether the UIImage != nil and uses the cached image (or downloads if nil).
A small difference is also that the caching code resizes the image before caching it to the exact size of what is displayed in the cell, whereas the image used in the sandbox code example is actually a bit larger than what it needs to display, which means it has to resize on the fly when scrolling as well. I read months ago that this could be a bit expensive to do, and I am also not sure whether it makes much of a difference in terms of then using a cached image instead of the sandbox-stored image and therefore more CPU intensive anyway (compared to what you save from caching with the caching code above).
I guess my question would be whether I should even bother with the caching code? Again, the new code won't immediately load images on a new launch, whereas the old code actually does because it's already in the sandbox. Since I am not reusing images, I have a lot of images to load (from the sandbox or cache) so I am not noticing a huge difference in speed. In fact, on my 3GS it's almost impossible to tell, in my opinion. The scrolling is not silky smooth, and I assume this is due to the large amount of images that I cannot reuse (different image for each cell). I am also wondering whether the sandbox method would get slower once there's 1000+ images in the folder, for example, eventually having it look through many more images than just 100 or so.
I hope I am making sense. I wanted to be pretty thorough with the details, and I am happy to give more details if needed.
Thanks!
If you have code that already works, and there's not a pressing problem, then don't change it.
If your scrolling actually is too slow, then perhaps you could use a mixture of ideas, and try to get the UIImage, and if it's not there, load it from the sandbox, and if it's not there, then download it.
The only good way to tell if there is any discernible difference in performance is to use profiling tools like Instruments (for measuring things like display framerate for the two techniques) or Shark (to determine hotspots in your code). There could be small differences in your exact implementation that could potentially cause significant differences between any general answer we could give and the actual performance you see in your application.
The thing that primarily concerns me with the "sandbox" method is not performance but disk space usage. Users won't appreciate you filling up their iPhone or iPod Touch with unnecessary files, especially if all the images aren't consistently used or if the set of used images changes often. Without knowing more about your application its impossible to guess how often these cached images would be loaded.
If you're testing locally on your own device, you might be on Wifi network. My recommendation would be to turn Wifi off for part of your testing to see how the two approaches perform when you have to fetch all the images over the cellular network. I would also recommend trying to find an older device (iPhone 3G or worse) because the 3GS does in fact hide potential performance issues that could be annoying for users on older devices.
I have personally used the LazyTableImages technique in my apps many times (provided it hasn't changed drastically between WWDC09 and the recent 'release') and find it to be just what I need. Caching images on disk wouldn't be an option in my case, however, and you shouldn't take my anecdote too strongly into account - profile your own code and use the results it shows.
Edit: The obvious answer is that accessing an in-memory cache is going to be faster than accessing the filesystem, but of course the final word on that is left up to profiling. If the images are already in memory, they don't need to be read from flash and parsed by UIImage. The traditional tradeoff comes into play here though - in-memory caching vs. disk space.
While it may be faster for you to store your images in-memory, you need to be very sure that you correctly handle memory warnings in your application (as you should be doing anyway!). Otherwise long period of use will lead to many, many images in your in-memory cache and trigger memory warnings and if your application is not built to handle these, at best your application will be killed by the OS due to lack of memory resources.
There are pros and cons in both approaches that you present - I suggest using elements of both in your app.
It's better to keep your images in memory and save them later (perhaps when your app quits). If you have a lot of images, it might be faster to use Core Data to save them, than as regular files.
It's also better to avoid doing any resizing on the fly, i.e. in your tableView:cellForRowAtIndexPath: or tableView:willDisplayCell:forRowAtIndexPath: methods or in any method that has to do with drawing your cells' content view. If you can, ask the image provider (content management?) to supply images at the size that your table view displays.
Need advice on how to debug this. I'm new with limited environments and have no previous embedded or smart phone programming experience so I could use some clues.
Already aware of:
Instruments, Clanger Static Analysis, manual code review, etc. Instruments seems to be very helpful in general but quite time consuming and freezes up a lot of the time! Clanger has also helped me a lot as well. It seems like I'm just consuming too much memory in general and I'm wondering what a good strategy is. Do I release some top-level objects? Is there a 'preferred strategy'?
Just wondering if anyone has tackled this successfully and if they have any other suggestions? Thanks all.
There are a lot of good articles for memory management in an iPhone app. Here are some useful links.
http://iosdevelopertips.com/objective-c/memory-management.html
http://kosmaczewski.net/2009/01/28/10-iphone-memory-management-tips/
https://cocoa-touch.blogspot.com/2008/09/memory-management-on-iphone.html
Things you should in general take care of
Release any variables which you do not need
Always handle didReceiveMemoryWarning and release any variables not in use
Stop any memory-heavy processes in applicationDidReceiveMemoryWarning like audio/video playing, UIImagePickerController etc
EDIT
This does not apply any more. imageNamed: had caching issues prior to 3.x OS versions. The issue does not exist any more and you should use imageNamed: (makes implementing retina display easier)
Do NOT use imageNamed: to create UIImage objects.
Basically you're receiving this warning because (unsurprisingly) the iPhone is dangerously low on memory. This can generally be for one of two reasons;
You have a memory leak.
You are allocating far too many objects and need to revisit your design.
For the first one you should run instruments and examine your memory allocations. This can really slow down your app (and requires additional memory) so try testing areas of your app one at a time. E.g. if you have multiple views switch between them a couple of times.
For the second you will have to examine things you are doing that could result in large memory allocations. For example if you're writing a Flickr browser you might need to cut down the number of images you have loaded at anyone time, or free up some unused ones when you receive this warning.
These are about the only general rules I can suggest without knowing more about your app.
Unfortunately there's no real way (that I know of) to get figures for current memory allocation from the iPhone OS. This makes it really difficult to isolate the areas of your application that are inadvertently memory hungry.