I need lessons in memory management. I have an application that uses multiple views (around 10), some of these are attached to tab controller. Problem is that I'm using images (many images that I load from a web service). I'm facing the following issues.
The memory keeps increasing when I scroll in the table view (why?) - I checked the CustomTableViewCell application from Apple's site, and it's showing the same signs when I run it with Instruments.
I'm using autorelease with many objects, but I see that these objects don't actually get released and the memory is wired. How can I get rid of these objects?
How can I tell the NSAutoreleasePool to periodically release the objects that are not being used? I think this can help me get rid of wired memory. But can I do that?
Is there any example by Apple or someone else (book or online articles) explaining how to use Instruments (in a little detail with example?) and to fine tune the application for memory and performance?
Thanks.
Now that we have the "just say no" answers to autorelease out of the way, I thought I'd add a tip on how to use autorelease more effectively. For better or worse not everyone's going to completely avoid autorelease-- if for no other reason than because Apple provides so many convenience methods that hand you autoreleased objects.
You can't just tell the autorelease pool to free up any objects that you're not using. There's no garbage collection, and how else is it going to know?
What you CAN do is to create a local autorelease pool and then release that when you no longer need the local autoreleased objects. If you have a block where you're creating autoreleased objects, you'll ensure they get freed by creating a local autorelease pool at the start of the block (just alloc/init it, no magic required) and then releasing the pool at the end of the block. And voila, and objects in the pool are also released.
Autorelease pools nest, so keep that in mind if you do this. If you release an autorelease pool, make sure it's the most-recently-allocated pool and not some other one.
The autoreleased memory is released when control is returned back to the system, but only when it chooses to. If you wish to force memory to be released use "release" which works there and then.
It should be noted that because of memory fragmentation that allocating and deallocating a block of memory may not seem to get you back to where you started in terms of measurable "free" memory.
Tony
For performance reasons, Apple recommends that you retain/release objects yourself whenever possible. autoreleasing them can cause excess memory usage as the autoreleased objects aren't always released immediately.
In other words, if you know you're done with an object, explicitly release it.
The UITableView has a way to reuse table cells that aren't being displayed anymore. That way if you only display 6 cells on the screen at once it doesn't keep on creating more as you scroll, but reuses the cells that have gone off screen. whenever you want to create a new cell, first query the tableview to see if it has any to reuse and if not then create a new one.
an example of this can be found on slide 55 of the standford iphone course note found here: http://www.scribd.com/doc/7671058/Standford-CS-193P-11Performance
According to Apple, you should not use autorelease and instead should retain and release objects explicitly as needed. autorelease will not release an object as soon as its function is over. If in the tableview you are using images downloaded from a webservice, try and cache these images and reuse them if possible. Another option is to only get those images which are being displayed.
Related
I wanted to know that how we gonna release all the memory retained by the view controller in app while logging out.
I checked my app using instrument that the allocations were not released while logging out though i am on my logging screen.
as after using the app for a while the allocation shown by instruments goes to 10Mb but after logging out I am on login screen but the allocation are still the same i.e. 10MB.
I dont know how to modify that logout function so that i can clear the data retained by the other views..
What you seem to want to do is to create your own garbage collector.
Change your mindset.
What you need to be aiming for are: objects which release any memory they are retaining in their "dealloc" method.
The important thing is to release every object you alloc, copy, mutableCopy, new or retain.
Also, use the Zombie tool in simulator to check for zombies (in addition to the Leaks and Allocations tools).
you say: "clear the data retained by the other views". But "the other views" should be clearing the data they retain.
I found that (for example) a UI object, like UIPickerView, is allocated and release frequently, even the corresponding dealloc method is called (proved by using Instruments), the Heap still grows up.
Is there a way to trigger the optimization of the autorelease pool to improve the whole scenario ?
My application needs to take photo, manage photo and upload to server. Over period of time, the Heap grows large and finally it crashes my application. ** I checked that there is no obvious memory leakage * with the use of Instruments.
Any Help or suggestion ?
Thanks.
You can create your own autorelease pool at places which make sense to your application. The following way of creating autorelease pools works with or without ARC.
// Stuff you plan to keep around after finishing the block below
#autoreleasepool {
// Load an image, send to server
}
// The images are released
It sounds like it is taking some time for your memory to get out of hand. If you are doing your work in the main UI run loop you should have autorelease occurring very regularly, so I'm not sure that another autorelease pool will help you. Perhaps you are keeping your references in such a way that they are not being released because they could still be used. Many leaks occur because objects are not removed from arrays, sets, and dictionaries.
In my cocos2d application I have run through it using instruments and removed all memory leaks. I have my game outputting how much memory is in use on the screen and it is constantly rising as the game progresses until I eventually run out of memory. The amount of objects on screen doesn't increase by very much each level. Its a fairly simple game so i should not be running out of memory so soon.
I am removing all objects from a level when it ends and reallocating new ones when a new level begins. Instruments tells me there are no memory leaks. When i run through instruments to show me where the allocations are the bulk of the problem doesn't seem to come from one place its all of my objects.
Any ideas what the issue might be?
Just because instruments doesn't show leaks, doesn't mean you're not still allocating memory you're not using. Pay attention to the ObjectAlloc graph and see if that is constantly rising without falling off.
If you allocate memory that you aren't using and can't clean up, that's just as bad as a leak, even though you haven't technically leaked anything because you've stashed some unused reference somewhere.
Look at how much memory you actually need to use or to keep for future use at any point in your app, then treat anything else previously allocated as a leak and fix it.
In Objective-C when using autorelease objects be wary of circular dependencies!
If you create object A and then an instance of object B and pass A to it, so that B retains A, and A also retains B (for example by adding it as child to A) you can easily setup a circular dependency and thus both objects won't be released.
Tip: add a -(void) dealloc method to all your scene classes, and set a breakpoint there. If you change a scene and its dealloc method isn't called after the scene transition has finished, you're leaking this scene (it's not released).
Try to find that leak by looking for a setup that's similar to the one I described above.
Be careful about autoreleased objects, since they are not released immediately. If you have sections with lots of allocations and autoreleasing, try using specific autorelease pools on them.
It happened to me when creating huge decision trees (using NSArrays) for a game AI.
A great way to check for objects that are aggregating in memory is to use Instruments' new (in Xcode 3.2.3) Heap Shot functionality.
Use the normal Allocations instrument against your running application. Perform a series of repetitive events that should come back to some known state (for example, go one level down in a navigation controller and come back). Every time you do this, click on the Mark Heap button in the left sidebar for the Allocations instrument (under the section heading Heapshot Analysis).
What this will do is mark the heap at each of the starting points for this repetitive action and compare the objects that have been created by that point with the objects that had been created by the time you marked the heap last. Only objects that have been created between those two points and are still alive in memory will be listed.
If you are accumulating objects, but they are either not leaks or are being missed by the Leaks tool, they should show up here. I've found a number of subtle memory buildups this way, particularly when you pair this with the UI Automation instrument to automate the repetitive actions you're testing.
The bulk of the problem seem to be that Sprites don't get released in cocos2d unless all actions have been stopped on those sprites. This is done using stopAllActions. Cheers for all the suggestions.
I have been hunting down memory leaks for some time in my app. As of right now, as I flip back and forth between two views while watching the memory monitor instrument, the real memory fluctuates between 5 and 6 megs. This is all fine -- as far as I can tell everything is getting released properly when I pop back off a view. However, the virtual memory continues to increase and my available real memory drops rapidly every time I push the view back onto the view stack (even though the real memory usage of the app isn't increasing). Eventually, this all leads to an out of memory crash. Is this a telltale sign of any specific issue, or am I just missing a memory leak somewhere?
EDIT: The odd part is, I get an out of memory crash while the app is still only using up about 5 megs of real memory.
Do not use -retainCount.
The absolute retain count of an object is meaningless. It is an implementation detail. It may be influenced by many factors well beyond your code.
You should call release exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).
See the Memory Management Guidelines for full details.
In this specific case, you are leaking memory but in a way that leaks can't find it. The objects that are leaked are still connected to your overall application's object graph somehow. Maybe through a notification, maybe through delegation, doesn't matter -- leaks sees the reference and concludes that the object might still be live.
Use the Allocations Instrument. Configure it to only track live allocations (since you don't care about objects that have been deallocated). Do some stuff with your app. Check out what Allocations knows about and explain why all those objects should stick around. You can use the data mining facilities to filter down to just your objects.
Anyway, you can also use the "Build -> Build and analyze" option to find suspicious non-conventional code.
Another reason why you may have memory lost in lower API layers is if you don't remove all your views from your view hierarchy (aka : not calling [view removeFromSuperview] everywhere). At least that's what seemed to have happened to me.
Note that most of time this isn't required, as you would simply release the main view and all its subviews, then rebuild it from the view controller when needed. Things start to get more tricky when you're not releasing the whole hierarchy but instead simply remove some of them from the hierarchy.
In that case, I came to the conclusion that you may have buffers or layers still cached in lower API parts, and in that case your Allocation instrument won't help you.
In order to monitor correctly you'll need to use the "Memory Monitor" (in System). You'll see that the "Physical Memory Free" line dropping close to 0 is the most reliable indicator that a Memory Warning will be issued.
Another advantage of using this instrument, is that you can attach it to a running process, thus making it possible to have console output and instrument running together easily.
Circular references also won't be counted in Leaks but you can track those in Allocations. Best bet is to fire up Allocations and get to a state where you think everything should be gone (or certain objects should be). If they're hanging around go dive in to them and look at where they've been retained and sort out the proper memory ownership/releasing.
As for Allocations, there are some things that it doesn't track that can affect the overall memory. Some of the things include some CGImage backing stores, some CoreAnimation stuff and some database stuff.
Have you used the "Leaks" Performance Tool? And check out the logs in Organizer to see if there's anything there.
Also look into the dealloc for the view controllers and make sure you are properly releasing all of it's objects?
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