In my iPhone app I have a very long table which I am loading from xml (online xml). This table shows one image and some text data in a row. I am also using Lazy Loading to load image.
Now in instruments there is no serious leaks, but overall memory allocation raising as I scrolling the table to down (means loading new images).
I want to know will this cause app crashing? My client is saying that the app is crashing on 3GS and iPhone 4, I am testing app on iPod 4G. I am not seeing any crashes but I can see high memory allocations in Instruments.
Please Help!
update -
Yes I am using resuable Cells. When the image loads I add them into the cells using this code -
- (void)appImageDidLoad:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader != nil)
{
UITableViewCell *cell = (UITableViewCell *)[tblView cellForRowAtIndexPath:iconDownloader.indexPathInTableView];
// Display the newly loaded image
UIImageView *mixtapeImage = (UIImageView *) [cell viewWithTag:TAG_IMAGE];
mixtapeImage.image = iconDownloader.appRecord.mixtape_image_obj;
}
}
You are right that i am not releasing the image because if I scroll up the table I have to add images in cells again thats why I am caching them in "imageDownloadsInProgress" dictionary.
Is there more efficient way of doing this?
The issue could very well be the images being cached, in which case the best solution would be to remove some images from the cache when you get a low memory warning. You could possibly write them to disk temporarily, which would provide a faster load time next time they're needed than re-downloading.
Do you respond to memory warnings? If you do, and you do it properly, your app will not crash.
However, if you are simply scrolling a table view, and memory is building up (does it keep building up, and by how much?) there is something wrong. It could be something as simple as an autorelease pool that is out of place (you are doing image loading), but it could very well be more serious.
Not seeing crashes on one device does not mean it will not crash on devices with a different state (i.e.: low memory state).
You could update your post with a screenshot of instruments, maybe the object allocations list, etc.
Memory increasing as you scroll is not a good sign. A common issue is that you are reusing cells and you keep piling elements on top of each other. Cells look fine because you only see the last layer of UI elements. These are not leaks because they are referenced by the table cell as parent view.
In terms of diagnostics, try the "Allocations" instruments to see if you have more live objets of some type (say, UIImages) than you expect. This is how you would do it:
In the Allocations instrument, using
the top-right search box, search for
"Image". Then look for the column
labeled #linving in UIImage. That
number is the number of UIImage
objects. That is a better compass in
to figuring out where are your
UIImages going. If at some point you
have more objects than what you
expect, and thease UImages are not
going away you have a UIImage leak in
your hands. An UIImage leak will kill
your app real fast.
quote from this answer.
Yes, it can cause a crash. Once you've taken into account the background processes, the shared libraries and your own code, your app only has a few megabytes of memory available on some iOS devices for custom data. If you blow through that, even if you can account for all of the allocations, then you will get killed by the low memory system. Or your app will, anyway.
You've already launched Instruments, which puts you in the top 1% of iOS app developers for knowing how your app behaves on the device. Well done! The next step is to understand why you're monotonically increasing memory usage as the table scrolls through. OK, so you lazily load images when they're needed, but do you dispose of them again when they're not? That should be easy to do using a UITableView with reusable cells, but perhaps you're caching the images somewhere and never emptying the cache. What happens in Instruments when you send a low memory warning in the simulator?
What does your cellForRowAtIndexPath method look like? Do you actually autorelease the cell you allocate in there?
There's no need for you to retain images - iOS is very good at caching results, and if it wants to release cells for memory management reasons, you should let it.
iOS versions pre-4.0 have lower limits for memory allocation. That's why the app crashes on your client's iPhone but not on yours.
Related
I have an image gallery which is developed using UICollectionView. After I select multiple images from the gallery and press 'Done'. Selected images will display in a UIScrollView (paging on) and those are full screen images that can be scrolled up/down to see other images.
1) Is it ok to have this amount of living objects and heap allocation, when starting the app.'
2) When I select and scroll through the images of UIScrollView allocated memory for images will added to the memory and not release. It will crash the app.
Here are the screens when I start scrolling up/down through the images. It will Increasing the memory consumption also other processes.
This is testing on iPhone5, using Activity monitor VM and Real memory going up.
Why don't you try to load the images 3 at a time, and not the whole set of images at once.
I mean you can set your Scroll Views array and add as many [NSNull null] objects to it as the number of images to be shown. Then, at a particular instance, have only 3 images in that array and after scrolling remove the unnecessary ones or replace it with [NSNull null] objects.
Profiling memory is tricky. The best instrument to actually use is the Activity Monitor, which will tell you how much live memory is really being used, unlike Allocations which will tell you more than you need to know.
Also, the maximum amount of memory is dependent on each device. If you really want to know if you're using a lot of memory, just test it on a device. You generally have a lot of flexibility, and the internal UIImage class does a lot of fancy caching and clearing of said caching for you.
I have an catalog developed for iPhone that is my first app. Because of it, I have some problems with memory leaks and the app crash down when I have more than 55 photos in catalog. (I will explain when it crashs)
I already tested with Leaks Performance Tools and I successfully fixed the leaks, but my app stills crashing.
My Data class have 5 NSMutableArrays. 1 have 50 UIImage elements for Portrait. The second have 25 UIImage elements for Landscap (catalog uses 2 portrait in 1 landscape image). Other have 50 NSNumber for reference image position of portrait Array to landscape Array. The other two have 50 NSString elements with (1) name and (2) address of icon images. One Data class object is created in AppDelegate (load of application).
I start the catalog in Portrait, making the views by passing the portrait Array (with UIImages). When device turns left, I remake the views (releasing old views) passing the landscape Array. In xCode, all of it works fine!!! In device, when I turn device left (to remake the views), sometimes (I noticed when I have other apps opened) the app crash down with this message:
"Program received signal: “0”.
Data Formatters temporarily unavailable"
I know that this message refers to Memory Leaks problem, so my question is:
Using SQLite to store my data (actually in NSMutableArrays) I'll gain memory performance? I'm newbie in SQLite for iPhone. Is there any other solution to store my data?
Thank you all, guys!!!
This question is less about NSMutableArrays vs SQLite and more about memory usage. A UIImage will typically consume a lot of memory and should be released when not needed which is usually when it is not visible. Your application may have 0 leaks but will still crash. You will need to register for UIApplicationDidReceiveMemoryWarningNotification notifications and act accordingly. UIViewControllers already respond to - (void)didReceiveMemoryWarning which you can override. Now for storing these images on disk for when you need to release the memory you could use SQLite or what I would recommend, just create a cache folder.
I like SQLite as a solution. It is easy to provide a pre-populated DB, and beyond that you simply hook your app into some methods that can Add/Delete/Update records.
Your issue isn't going to be solved with SQLite - the problem is memory management. Get that wrong, and it doesn't matter where you store your data.
Separate the 2 concerns - displaying vs storage. Get the displaying to work right, then worry about where to store the data.
I'm developing an app which uses a UIScrollView to show a list of images based on search criteria. Using a button the user can load more images.
When testing on an iPhone 4 the ViewController receives a memory-warning at ~750 images. When testing on an iPod 2nd generation a memory warning is received at ~150 images.
My understanding is that when didReceiveMemoryWarning is called, one can free memory by releasing objects but recovery from low memory is not guaranteed.
I've implemented didReceiveMemoryWarning and release basically all objects. In instruments I see memory usage drop back to ~3MB. The first time the iPod reaches its memory limit all goes well, memory is released and the app resumes normal operation. The second time however, when didReceiveMemoryWarning is called, I can see the objects released, but the app crashes anyway.
So, how do I make my app crash proof? I want to make sure that all devices running the app can load as much images as memory allows but I also want to make sure that the app doesn't crash.
I would prefer the app never to reach didReceiveMemoryWarning and set a limit to the number of images that can be displayed, but how can I determine how many images each possible device should be able to load?
Furthermore, the size of the images is not guaranteed. While testing I come to this arbitrary number of 150 on an iPod, but what if the images on the server at some point in time are twice as big? Then the app would probably crash at 75 images.
Any sugestions?
First off, what you probably want to do is not display all your images all at once. You rather, probably only want to disable the images that are currently visible, plus a few that are off screen preloaded for when the user scrolls to that location.
This is much the same way as the photos app works, how UITableView is implemented. Basically it boils down to this:
You have your main scrollview, and inside it, you have individual cells. These cells are small views that are added as subviews to your scrollview at specific offsets. You then add your images to these cells.
When a user scrolls the scrollview, you first ask the scrollview to dequeue a new cell for you, much the same way you'd ask a table view to dequeue a cell for you to use. This saves the cost of an allocation, if one has been recycled. If you cannot dequeue one from a recycled set, then what you have to do is quite simple: allocate one as you are doing currently.
Furthermore, to implement this cell recycling, what you need to do is see which cells are visible on screen. If one or more cells go off screen, you add them to the recycled cells NSSet which you create. This set just holds cells for later recycling. There's some sample code Apple has which demonstrates this, and it's called PhotoScroller. It also is demonstrated in a WWDC10 video, session 104. I suggest you watch it. Ignore the parts about tiling, you don't need to know that for your purpose.
Once you have this in place, this will force you to set up your cells only when they're needed, which is also another key aspect of this behaviour.
Finally, when you do receive a memory warning, just drop the recycled cells set. If you ever get high enough that this matters, that is, you'll save a few megs of memory. :) (Do not forget to implement it though, ever, when you hold onto temporary data that you don't specifically need around...cells which are not visible on the screen are a good example of this, as are caches.)
You should lazy load your images and only load the images you need at that time. Your app can't show all those images on one screen anyways, so on your scrollview you should only load those images that can fit on the screen and maybe a few around that, and as the user scrolls to release the images it no longer needs.
I have two queries
I was running a sample app which having single view controller in it implemented. When I check the memory using Instrument it was showing 3.66 MB
. Wondered why it is taking so much of RAM as there is nothing much heavy in app.
When I have added UIImageview with the Image having size of 25 KB,then Memory uses go to 4.24 MB
[ I come to know the reason behind is "image is unpacked 320*480*4 = 580 KB" but need to debug more on this & it remains in cache ]
Along this I have also observed two scenarios
When we uses api [UIImage imageNamed:aName] for loading image, then calling [UIImageview release] doesn't have any effect.
But When we use
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:aName ofType:nil]];
Some memory is cleaned up when I call [UIImageview release]
In my app , I am going to use lot of images and that will cause a low memory and will crash the app.
Please provide me some ref or path to analyse why this behavior.
Thanks,
Sagar
Trying to fit your app in memory is a losing game. It'll lead you down weird paths of trying to figure out which sort of device you're running on, swapping in and out resources based on that, etc, etc.
The better option is to design your memory structure for ditchability, and then support a fairly harsh ditching regimen when you're notified of low memory conditions. Go ahead and use memory--it's there for that--and let the low memory warning be your signal to prune out unused resources.
A lot of people seem to feel bad that their application generates memory warnings. That's silly. The design pattern here is, eat all you want, but respond appropriately when you're told you're overweight. Given you're running on a broad range of devices with a broad range of memory profiles (an iPhone 3G has 1/4 the RAM of an iPhone 4 for instance), the best way is just to be sensitive to when you've filled memory.
The main hurdle you'll encounter is recovering from having ditched data. I find what works best is to explicitly set UIImage objects to nil, and then test for nil before using them, reloading them from the bundle or the network or whatever if necessary.
All that said: [UIImage imageNamed:] supports ditchability, but you don't have control over it. When a UIViewController subclass gets a memory warning, it will ditch cached UIImages that you've created with that method, but nothing you can do will make them go away until then. Even assigning a tiny something to the UIImage in question won't help because it's cached associated with the "name" that it's "Named", not the object that it is assigned to. So that method is good for images you're going to reuse a lot, but even so, it will get pruned when the time comes, and you need to respond appropriately.
Images, loaded with imageNamed, are cached in memory by UIKit, and images, loaded with imageWithContentsOfFile are not.
My GUI for an iPhone app uses numerous UIViews. The user "flips" through these views when they tap a button to go forward or backward. The views are stored offscreen and are added to an actual view only when the program needs to display it.
During the flip process, the program tells the parent view (a uiscrollview) to remove any existing subview using the removeFromSuperView method, and then adds the new subview, which is the new page that the user should see.
However, after several repeats of this process on the device, the program crashes with gdb exit status 101, which I found is caused by an out of memory error.
I tried diagnosing this problem using the Leaks tool, but to no avail. There is only 1 or 2 small memory leaks and the total mem usage on the device by the program is only 2.5 mb. Is it possible that video memory, not system memory, is running low?
I came across this post regarding backgroundColor and mem usage, but I need further explanation. Should I reduce setting the backgroundColor to prevent the UIView's CALayer from hogging too much memory?
Do you have access to the iphone sample code on apple? Sounds like the PageControl Sample Code program is a good example of what you're looking for. And the sample code programs don't have memory leaks or any such problem :) Link here
When you were using instruments, did you check the ObjectAllocations? I've found that to be more useful than the leaks tool (object allocations is one of the tools leaks includes though). I would think that if video memory were running out it would be a different error, but I could be wrong.
Where are you storing all these views? Specifically, do you have some array (NSArray) that has these views when you flip through them?
The views won't get deallocated unless their reference count goes to zero. Your `[[UIView alloc] init] makes the reference count at 1, adding it as a subview makes it 2, and removing it from a subview makes it 1 again. Seeing as you don't get told of a specific leak, it seems that you're not really leaking as much as storing it somewhere.