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.
Related
I have a universal app that is essentially a list of articles with images and text, and menu under the left side of the app. I have google analytics in, as well as parse's framework.
The only difference between the app on the iPad and iPhone is that the side menu is always visible on the ipad, and a few interface objects are moved around. (different cell layout for the list--same content, though).
The images are loaded asynchronously using a set of classes that I wrote to download/save in an NSCache object and on the disk using a NSOperationQueue. (disk cache is wiped when the user leaves the app). The NSCache is set to max out at roughly 10 mb. (assuming image size is image hight*image width * 4 bytes per image). (code here is identical for both, so it shouldn't be the culprit, but it is a large chunk of the apps memory use).
I was having some trouble with memory warnings/crashing on an older iphone4 running iOS 5.0, so I ran the app with the Activity Monitor Instrument, and noticed something very odd:
On the iPad (an iPad 2 running iOS 5.1) the app launched, loaded the images that were visible immediately, and was using about 16mb of memory.
On the iPhone4 it launched, loaded the visible images and was using about 35mb of memory--way more than I would expect.
In order to check if it was an OS memory issue, I also ran the app on an iPhone5 running iOS6 and it used about the same amount as the iPhone 4.
I checked my media and the storyboard files to see if anything was different at all, and I could not find anything that could change the memory usage in any significant way.
Is there any way to reduce the memory use of the app on the iphone? I can think of no reason it would use so much memory.
Very difficult to see.. as one person stated pay attention that retina devices will use more memory according to the source, if in the bundle you set #2x images it will load them, and they use more memory.
Have tried to profile the Virtual memory using allocations?
Using memory is usually fine even if it fires a memory warning, the problem is how you respond to it, when it comes does it free enough memory? try with the simulator to simulate a memory warning. Pay attention that sim uses more memory than device.
One other point is that since ARC is difficult to create leaks, but it's easier to create retain cycle and abandoned memory. A correct object life cycle should end with object deallocation.
You say that you use NSCache and load images from the net async, I've got 3 suggestion for you :
Do you know the original image size on the source? maybe on the iPad source images are smaller than on iPhone. A correct approach after you download an image will be resize it according to the really needed size (I'm mean redrawing non just stretching) you ca achieve that with Quartz or using ImageIO
I never understood the behaviour of NSCache after memory warning, Apple says that it will flush the memory but after some test on iOS4 (I don't know now) I don't agree. I've created my own subclass that observe for memory warning and flushes memory
Are you totally sure that you are getting back image from the cache ?
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.
I am working on an App that is already been made but Memory Management was not considered in the development stages.
So what can I do to keep the App memory usage low as soon as I get a memory warning?
Is there any general tool or some piece of code that I can use to release any unused memory?
Two things.
First, if you're using any sort of view hierarchy (tab bar, UINavigationController, or something you've rolled on your own), the message is going to propagate upward. That means one handler for memory messages in your root-level UIViewController subclass can handle memory events for the whole app, which is very handy.
Second, you want to go after the low-hanging fruit. In the app I'm currently working on I have a couple different arrays of dictionaries that contain my app data, and each of those dicts contains both a thumbnail and a larger image. Obviously those make up the bulk of the bits I'm keeping in memory. So the first thing my root view controller does when it gets a memory warning is go through those data sets and set those images to nil. Because they're retained properties, they get released when the setter is called and the images are freed from memory. Then I have functions in my view controllers to notice the nil-ness of those image fields and reload them from the server.
By the way (okay... two things and a "by-the-way"), memory warnings aren't a problem. Some people seem to feel bad about getting them, want to redesign everything about their app so they never get one. That's really not necessary; even the best-designed app will get warned about memory occasionally, just because of the unpredictability of the background apps on the device. The important thing is to handle them well.
Xcode can be combined with the Instruments tool to show you the places where your application is leaking memory, i.e. where reserved memory is not released properly. CIMGF has a solid tutorial on this: http://www.cimgf.com/2008/04/02/cocoa-tutorial-fixing-memory-leaks-with-instruments/
You should have a look at the method
- (void)didReceiveMemoryWarning
of your UIViewControllers. This method is called when you receive a memory warning. Here you can release objects currently not used. But it's your part to determine what is used and what not.
The "Build and Analyze" feature of XCode is a tool you could use to see if the code contains any obvious memory leaks.
You should have a look at the small section "Memory Management" in the UIViewController class reference:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html
Also an important document is the "Memory Management Programming Guide":
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
My iphone app plays a slide show made up of 5 user images. These images are stored using core data. I was noticing that memory was building up every time a different slide show was played and it was not releasing any of the previously played slide shows.
These images are showing up in Object Allocations as CFData. So I tried releasing this data in the dealloc method
CFRelease(slideshow.image1);
CFRelease(slideshow.image2);
CFRelease(slideshow.image3);
CFRelease(slideshow.image4);
CFRelease(slideshow.image5);
This releases the previous slideshow great...BUT when I go back to view that same slideshow again, it crashes.
I am guessing that I need to alloc/init these images again, but I am not sure how? Or maybe I should be managing this memory in a different way?
It sounds like you're CFRelease-ing data that you shouldn't, and since you're mucking around with the NSManagedObject, you inevitably get a crash when Core Data goes "WTF?"
By "it was not releasing" are you seeing a memory leak, or simple memory usage growth? If the former, then we'll need more information, especially if Core Data is leaking, you might need to file a bug report (which is unlikely). If the latter, then there's much you can do, since Core Data is in charge of its own memory management.
It's possible you could use a NSAutoreleasePool to optimize but I can't say more on that.
I have an app that has a tabBar Controller and a navBar Controller. It has ~8 views (a variety of web, table, standard, mail, address etc.), some created using IB some created using XCode to make the table views. I've ran the memory leak tester and it doesn't have memory leaks. It can crash at anytime on any of the views, If I flip back and forth between views and use some of the functions it closes the app.
I assume that either I am running 1) out of memory or 2) not releasing views correctly, which causes the app to close. The app is simple so I don't know how I could be out of memory and I've reviewed the code to the best of my ability for releasing the objects correctly.
So Here is my list of questions:
1) What and How to use some of the other debugging tools (or tell me what tools/files I should be looking for using)? I would like to narrow down the problem to its source.
2) What is the best practice for releasing these views? How?
3) How much memory do normal apps use? Is there a number that I should stay around? How do I verify that in the simulator? the Allocation tool?
Feel free to point me to apple docs or other stackoverflow questions that can help me.
UPDATE: It appears to only be crashing one view is used, which has a table view with custom cells... The cell are populated from a plist file... this view worked fine a few days ago, I notice that some cells do not have data from the plist file... it could be a plist file problem with not storing proper data. I'll continue to work on it.
UPDATE #2: I went back to older rev of my files, to when this particular tableView worked just fine (pre 3.0) and guess what it works just fine, I change the simulator to 3.0 with this rev of the app and bam crash on this tableView shows up. Thanks for the help so far, I'll try somethings mentioned below and let you know what I find. If you have some tips on why a tableView w/custom cells from 2.2.1 to 3.0 would start crashing, I'll take them. If I can't get anywhere I'll post the code soon. BTW, I mis-spoke above, I thought it wasn't crashing in the simulator... I was wrong it is.
Solution: thanks for the troubleshooting tips the fix was quite simple, but it's odd it didn't crash in 2.2.1... it should have crashed a long time ago for the problem, I was releasing an object one to many times in my custom cell... duh.
On the first and second generation phone's you really don't want to be going over about 20 megs of real memory usage - once you get over that you are at risk of being killed by springboard.
One of the big culprits I've seen is autoreleased memory, since the autorelease pool can hold onto memory a lot longer than you would really like - if you are using a lot of autoreleased objects that can be a potential problem. You can improve this by doing more explicit retain/release where possible and by creating local autorelease pools manually and releasing them after doing a more intensive operation with a lot of autoreleased objects.
The most effective way to keep track of real memory usage I've found so far is running a debug build on a test phone and running with Activity Monitor. That will give you a clear idea of how much memory is getting taken and held onto by your app. As well as how much is being used when it crashes on you.
You can run with Activity Monitor in Xcode on the Run menu -> Start With Performance Tool -> Activity Monitor.
One other very useful tool is the CLang Static Analyzer that you can run against your code base and can give some very helpful memory management information. As mentioned here.
One thing I would try is putting some debug messages into your didReceiveMemoryWarning method(s). That way, if you are running out of memory, you'll at least have some warning.