How to debug large UIView memory allocation - ios

I am trying to reduce memory usage in my app, and analysis with Instruments shows that a UIView drawLayer:inContext: is allocating 2.25 MB. I assume the allocation is done right before my code is called, and is due to an incorrect UIView or CALayer size somewhere. But none of my code is involved in the allocation (see picture below), therefore I have no idea how I can debug this. I have already checked all my views and layers, I think, and I do not see anything wrong.
Any ideas are appreciated!

Don't worry. The system is allocating a backing store for the layer which happens to be 640 * 960 * 4 bytes.
If you don't leak the layer or view, you'll get your bytes back eventually, at the moment your view is unloaded.

iOS apps don't just suddenly crash when they run low on memory -- they unload unneeded views and send memory warnings to the view controllers. If your app's crash seems to be related to memory, make sure that you're handling low memory situations properly: implement -didReceiveMemoryWarning and -viewDidUnload to get rid of data you don't need.
Views can use a lot of memory. UIViewController will release its view when it needs to, but if you have another strong/retained pointer to the same view, the functionality that your view controller inherits won't know to release that, and the view will never be deallocated even though it's not needed. It sounds like this may be what's going on in your case, since it's a large block of memory that's about the right size for a full-screen view. Look at your view controllers for additional pointers to your view controller's view (or any other view) and make sure that you set such pointers to nil or release them (depending on whether you're using ARC or not).

Related

Is it safe to leave unreachable ViewControllers in an app?

I have made an iOS Swift application with some ViewController(s) that are not entirely finished, so I haven't provided methods for them to be presented yet.
Is it safe to leave these ViewController(s) unreachable?
Xcode will display a warning stating that the ViewController is unreachable in the Storyboard, but since it is only a warning, it doesn't affect the build process.
Also...
Do I risk getting my app declined by Apple if some ViewControllers are inaccessible?
Is it safe to leave unreachable ViewControllers (I mean, will it cause any crashes or bugs?)
I want to avoid getting rid of the ViewControllers because I will need it in the next version.
Does this differ from leaving unreachable XIBs, and leaving unreachable Swift files that hold the class for the ViewController?
A view controller in the storyboard has effectively no overhead at runtime unless it is actually loaded, at which point it is turned into an instance. It occupies a pair of nibs (one for the view controller, one for its view), which take up some space in the built app; but the runtime never even bothers to look for those nibs if you do nothing that loads the view controller's nib.
A code file for a view controller that is never instantiated has effectively no overhead at runtime. It has some overhead at compile time because the code has to be compiled, so it adds a small amount of time when you build. The compiled code takes up a tiny amount of space in the binary.
Thus I think you can conclude there is no downside to what you're doing.

Memory usage increasing

I have a quick question- does it matter if the memory that is used by an app while it is running increases slightly (0.1mb) every single time a view controller is loaded? I have a game which has an infinite level, and if the player loses the view controller basically refreshes (e.g. all timers invalidated) and the main menu controller is loaded. Then every time the infinite level is restarted, the memory (shown in the debug navigator) goes up. So the first time the level is played it is 226 mb, the second it is 226.2 mb, third it is 226.4 mb etc. Is this a problem?
What is probably happening is that there are a few strong references to Views/iVars/Properties still left dangling when you release your infinite level view controller (by dismissing/removing from superview). Try to release all your properties and instance variables just before you release your view controller. You could also try to define all your IBOutlets (which don't get removed from the view) as Weak type, so they get released when the view controller is dismissed.
Some points you can remember as a checklist for memory management:
Any property/variable with a strong/retain type should be released by the user. ARC does it automatically, but sometimes it does not release correctly (Don't ask why).
Instance variables are by default a "Strong" reference type, which means you have to release them manually
IBOutlets that remain in the view and you don't removeFromSuperview, can be of weak type, since the view holds a strong reference to it.
(if you do not have ARC on) Make sure that you have an NSAutoReleasePool block so that it releases all local variables, thereby preventing memory leaks.
Your problem, while not serious at the moment, could become serious quite soon. The average iPad/iPhone starts giving memory warnings around 300 MB, so if you start adding any more features to your game, this could become a big problem.
Hope this answer helps.

UINavigationController pushviewcontroller memory management

I have a UITableiew listing n number of contacts and from Table view delegate didSelectRowAtIndexPath I am navigating to a 'Contactview' UIViewController by using UINavigationController pushviewcontroller.
For an instance if I navigate the first contact to Contactview, Live Bytes memory goes up from 1 MB to 3 MB. Then when I tap on the back button the viewcontroller delloc method is called but the memory still stay around 2.95MB to 3MB . My question is when the viewcontroller delloc method is called the memory of the viewcontoller should be released right ? Am I wrong anywhere ? Please suggest me if I am wrong. And I am using ARC project.
Thanks in Advance..
If you push your navigation back and forth and you see memory climbing unlimitedly, you have a memory management problem. Even with ARC, you may have abandoned memory. You can detect it using the Allocations template in Instruments.
In Instruments, put the application in a well-known starting state (for example, showing the table view).
Click Mark Heap button under Heapshot Analysis.
Navigate your controller back and forth once.
You will see a small increase in memory usage in the allocations graph. This is normal, internal caches may be storing some information.
Click the Mark Heap button again.
You will see a number of objects in the Still Live column.
Repeat steps 3-6 many times and see if there are "still living" objects after every iteration.
If there is an almost constant number of still living objects in each heapshot, click the right arrow button in one of the heapshots and you will see all the objects that are still living. Look for objects probably created by you, select one, expand it, and select its memory address with a simple click. Then click the Extended Detail button to see a stack trace showing where the object was allocated. With this code context I'm sure you will understand why your memory was abandoned.
See.. one thing ARC will release it the contents some where in future right.Its Automatic right.. how can expect the ARC to do the Gatrbage collection after class will disappear.It might take time to free the memory.
Did you check retainCount? is that showing your desired value?
UIImage caches images for you as an optimisation, so this is expected behaviour.
If you wish to confirm that this is the case, for peace of mind, you can force a low memory warning (Under the Hardware menu for the simulator). This should get UIImage to throw out its cache.
You can also use this private method, but of course throw it out before submission.
[[UIApplication sharedApplication] performSelector:#selector(_performMemoryWarning)];
You might own a strong reference for the view controller elsewhere in the code. You should be sure if it's really deallocated... If any other object has reference to it beyond the navigation controller it won't be deallocated. Try override dealloc. (You could override dealloc in an ARC project as well, you are only not allowed to use retain count manipulation calls.) To be sure if dealloc is called put some logging or something debugable code into that method.

Does UIImageView release resources when not in view?

Does UIImageView automatically release image resources when it isn't in view? And perhaps when the app gets a memory warning?
If not, I'm considering writing a subclass (e.g. SmartReleaseImageView) that does so, to be used in particular situations where this would be beneficial. I was thinking of behaviour along these lines:
When SmartReleaseImageView receives setImage message, it registers itself with a manager e.g. SmartReleaseImageViewManager.
When app gets a memory warning, SmartReleaseImageViewManager loops through all its SmartReleaseImageViews and checks whether any of them aren't added to a superview, or checks whether any of them have a frame that is culled due to being outside of the bounds of the main window.
When SmartReleaseImageView detects that it has come into view and has been released, it loads the image again. So perhaps, it would need to have a method like setImageURL rather than setImage in the first place.
Is this kind of behaviour already built into UIImageView? Or does it exist in a 3rd party version anywhere? Or is there a problem with idea?
(I'm writing a UIImageView-heavy app, and it would be nice to have a global catch-all solution that would help with the memory situation, rather than adding lots of extra code to my UIViewControllers.)
EDIT: Answers so far suggest that UIViewController should be responsible. This is true, and I guess my particular case is atypical. In my case, the UIViewController can contain a lot of custom views (with their own hierarchy) that it doesn't necessarily know the structure of, and which go in and out of view frequently. So, it's difficult for it to know when to release its resources. But yes, perhaps I should find a way for it to deal with the problem itself...
Well, you actually have this automatic management implemented in the UIViewController. Since UIImageView is a subclass of UIView, your view controller should be able to manage it automatically.
Memory Management
Memory is a critical resource in iOS, and view controllers provide
built-in support for reducing their memory footprint at critical
times. The UIViewController class provides some automatic handling of
low-memory conditions through its didReceiveMemoryWarning method,
which releases unneeded memory. Prior to iOS 3.0, this method was the
only way to release additional memory associated with your custom view
controller class but in iOS 3.0 and later, the viewDidUnload method
may be a more appropriate place for most needs.
When a low-memory warning occurs, the UIViewController class purges
its views if it knows it can reload or recreate them again later. If
this happens, it also calls the viewDidUnload method to give your code
a chance to relinquish ownership of any objects that are associated
with your view hierarchy, including objects loaded with the nib file,
objects created in your viewDidLoad method, and objects created lazily
at runtime and added to the view hierarchy. Typically, if your view
controller contains outlets (properties or raw variables that contain
the IBOutlet keyword), you should use the viewDidUnload method to
relinquish ownership of those outlets or any other view-related data
that you no longer need.
source: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
Short answer:
UIImageView does not release resources, never.
But all your views (including UIImageView) are released when the system needs more memory. Note that you have to release your views in [UIViewController viewDidUnload].
Edit:
Unfortunately, it doesn't work when the controller is not displayed. It that case I suggest to purge the components manually in viewDidDissappear (call viewDidUnload manually and remove components from the view hierarchy).
Anyway, this won't help if one view controller has too many images in its hierarchy. In this case I would recommend to create a set of UIImageViews and reuse them, in the same way as UITableView reuses its cells.

How to resolve memory crash

I'm creating an application which features having multiple animations.
There are 50 pages and on each page there is a different animation and each animation uses many images.
I'm using UIPresentModelViewController for presenting the views and
am changing images using NSTimer.
When I swipe continuously the application crashes with this message:-
Program received signal: “0”.
Data Formatters temporarily unavailable, will re-try after a 'continue'.
(Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
I searched a lot but couldn't find any proper solutions to this issue.
Just check within your code that you are making some mistake by adding new view every time but forgot to release it...
You need to look at (and perhaps post) the stack trace when you crash. And the code that changes the image. This sounds like memory bloat (not a true leak in that someone is still referring to memory). The Analyze menu item might catch something (and you should definitely run it), but you may need to run the Allocation instrument and look at heap checks. See http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/ for more.
This sounds like a stack overflow to me. In the "Other C Flags" section of the project's C/C++ language settings add a flag for "-fstack-check" and see if that turns up any unwanted recursion.
Signal 0 is usually due to memory low as the app using too much memory. Check whether memory warning method is called or not.
The data formatter thingy failed to load might be due to there's not enough memory to load it..
50 views like you describe sounds like a big memory hog. So I suspect memory management is unloading some views. Then when your program needs the views, they are not there and your program crashes. The error message doesn't quite fit this, but it may not be accurately telling you what the problem is.
Consider the following possible scenario, and see if it fits how you coded this program.
In order for the OS to manage memory, it can unload views and reload them as needed. When this is done, the methods viewDidUnload, loadView, and viewDidLoad are called.
viewDidUnload:
This method is called as a counterpart to the viewDidLoad method. It is called during low-memory conditions when the view controller needs to release its view and any objects associated with that view to free up memory. Because view controllers often store references to views and other view-related objects, you should use this method to relinquish ownership in those objects so that the memory for them can be reclaimed. You should do this only for objects that you can easily recreate later, either in your viewDidLoad method or from other parts of your application. You should not use this method to release user data or any other information that cannot be easily recreated.
loadView:
The view controller calls this method when the view property is requested but is currently nil. If you create your views manually, you must override this method and use it to create your views. If you use Interface Builder to create your views and initialize the view controller—that is, you initialize the view using the initWithNibName:bundle: method, set the nibName and nibBundle properties directly, or create both your views and view controller in Interface Builder—then you must not override this method.
Check the UIView Class Reference --
viewDidLoad:
This method is called after the view controller has loaded its associated views into memory. This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method. This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
You may have inadvertently initialized these views in your init methods rather than in your loadView methods. If you did this, then when the OS unloads a view (you will see viewDidUnload is called) the memory associated with the view and all subviews (all of the images and animations) will be unloaded. This saves memory, but when you need one of those unloaded views to reappear, loadView will be called first if the view had been previously unloaded. If your view setup is done in the init methods rather than in loadView, then the view will not be setup again. But if the view setup is done in loadView method, it can be recovered after memory management unloads it.
There is one and easy way to find out leaks that is hard to find via leaks instruments and so on - Zombies analyser. It shows every unlinked memory in your program, and you can easily detect leaks and optimize code in minutes.
If you're using lots of images for a single animation you're doing it wrong. You should have one, or several very large images and then just show a portion of that image. This way you can load very few images, but have the same affect of having many images.
Look into cocos2d or other frameworks that are popular for making games, as they will be much more efficient for animations than just UIKit.
Find out the reason for memory crash using instrument tool and then refactor the code with best practises with recommended design pattern. There is no unique solution for this. Thanks.

Resources