I am new to IOS and coming from pcs I am trying to get a feel for managing memory and battery resources.
I have a UIImageView subclass which is is very light (it's an image placeholder with a handful of methods). This subClass is repeatedly added to, and removed from, several root views. I hold an IBOutlet reference to the subClass on each root view.
Would you:
Simply add/remove the subClass from the root view (and keep it in memory)?
Or
Create and destroy the subClass instance each time (freeing the memory but extra work)?
Is this worth considering or am I worrying over nothing?
Would your answer be the same if the UIImageView subClass was very large?
Is there a way of measuring these matters?
In general, you can use UIImageView with disregard on iOS. UIImageView is not much more than a clipping region with some methods for dealing with images.
The resource which takes up more memory is the UIImage contained by the UIImageView and these are cached by iOS.
So there is little cost to creating UIImageViews and destroying them, just take care that you dealloc them and don't leak memory and you should be fine unless you have hundreds of them.
The subclass being "large" doesnt matter, the code in a class is never loaded more than once. If the class has alot of extra state - that will take up some memory but I cant image a whole lot of that in a UIImageView.
You better just keep it in memory. User experience will be much better if you don't slow down the device by continuously recreating the image view. One single poor UIImageView instance is not memory heavy enough to worth the time and effort to recreaty all the time.
Keeping it an memory to improve performance isn't as much of a hit as you would think - taken from the other answers you have. But you should remove it from memory if you get a memory warning, and provide a way to bring it back to life as needed.
I would go with your first option, keeping it in memory. This is just because I think it is handy to keep my views alive and reuse them. This means that they will remember their state and content and that helps out in many cases. I usually write methods to reset the content or refresh it when needed.
Keeping it in memory might also increase the loading of the view slightly, but usually you do not notice the difference, and I see people using both ways.
And yes, I would say you are worrying a bit too much, especially if you think this decision would affect battery.
Regarding memory management, keeping the imageview in memory or releasing/recreating consumes the exact same amount of memory as long as you only have one imageview that you are using. The only difference is that you are allocating and releasing it repeatedly if you are recreating it.
You could however get memory issues if you start creating new imageviews every time the user opens them and never letting go of them, but that means you are doing something fundamentally wrong in your programming.
As long as you know what you are doing, no need to worry about the amount of memory in a case like this - there's plenty. Start worrying if you are handling large images.
Especially if you use ARC there is not much to worry about, just start hacking away. If you are managing memory manually, I do recommend trying to reuse stuff because that causes less headache and risk of giant leaking. Use leaktools and analyze tool to make sure in this case.
Related
I am building an iOS app with one of those "hamburger menu" type drawers that open up to a list of options of the left. Like this:
Each time you click on an item, for example "settings" it loads a new viewcontroller and displays it on the main view controller. Now, the question I'm wondering is whether or not I should be releasing the viewcontrollers each time a new item in the menu is clicked.
For example:
You are viewing Inbox
You click Settings
I release InboxViewController and alloc init the SettingsViewController
I make the SettingsViewController the main viewcontroller
I'd like to keep all the viewcontrollers in memory, because I think it would provide for a more smooth transition from one to the next if it was previously allocated, instead of having to wait each time to allocate it.
I am using ARC
Is this bad practice? I might have 6-7 viewcontrollers in memory.
Looking at the SDK, Apple makes both choices: UINavigationController keeps the whole stack of VCs below the top, while UIPageViewController aggressively releases any page except the current one.
This is an example of a "speed/space" trade. Precomputing and caching objects will be faster (once running) but occupy more memory. Releasing more aggressively and building (or rebuilding) will incur some run time cost but occupy less memory.
The question might also be an example optimizing too soon, or unnecessarily. For a handful of typical VCs the allocations are quick and the memory footprints are (ought to be) small. Changing approach will likely have insignificant impact on either speed or space.
I'd start with whichever way is simpler (probably allowing VCs to be released passively is simpler) and see if there's a demonstrable problem that needs solving.
If you consider what you're doing, it's really no different than a UITabBarController. The views don't load until they are viewed the first time, but then are kept "alive" indefinitely. I would think as long as you keep the number of loaded view controllers reasonable (single digits) you'll probably be fine, with the one caveat that if they are all doing some intensive processing/loading/etc., it could become problematic.
I don't necessarily think keeping all the ViewControllers in memory is a good thing, unless the View contains objects that take a long time to fetch (i.e. opening a UIDocument or from a NSURLRequest).
Hope that helps!
I'm new to iOS development.
I'm building a simple bus schedule app that makes a HTTP request, parse XML, and display/save data. I have four table view controllers and two view controllers.
When I start the app, Xcode memory report tells me that its memory usage is ~18MB, which is weird since it's just a simple app. I've looked at similar apps on the app store but they were all less than 10MB. Since it's a bus schedule app, I have it make new requests every 30 seconds to update the time. I noticed that each time I change view to look at another schedule, the memory usage increases and it may go up to 50MB or more.
I looked at Xcode's instrument and it looked like there was no leaks. I also looked at allocations and it looked like live bytes kept increasing every time I switched views.
I am kinda stuck from what to do from here. Can anyone guide me please? Thanks in advance.
Use Heapshot to find memory creep. (see: bbum blog)
Basically, their method is to run the Instruments allocate tool, take a heapshot, run an iteration of your code and another heapshot, repeating 3 or 4 times. This will indicate memory that is allocated and not released during the iterations.
In this case, take a heapshot (called something different now) between downloads.
To figure out the results, disclose to see the individual allocations.
If you need to see where retains, releases, and autoreleases occur for an object use Instruments:
Run in Instruments, in Allocations set "Record reference counts" to on (you will have to stop recording to set the option). Allow the problem code to run, stop recording, then search for the object of interest. After that, you'll need to drill down and you will be able to see where all retains, releases and autoreleases occurred.
First, take a look at heap shots as #Zaph suggested. Well worth your while in terms of seeing what's being allocated and not released.
Another technique I use is to use instruments filtering options to filter the display for just the classes in my app. Then, I look for classes which have unusual number's of living instances. For example, most view controllers usually have only one active instance. If there are more, then something is retaining them. Blocks and notification listeners are often the cause.
In your example screen shot, I noticed two things that I would investigate.
Firstly, you have 365 living core animations taking some 30M. Not sure why, but worth thinking about.
Secondly, near the bottom, I noticed 166 table view cell scroll views. Sounds like a lot. I can't see how many living table view controllers you have, but I'm wondering if they are not reallocing. Filtering this list will help establish what's not being dealloc'd.
Finally, leaks can be useful in finding issues, but most of the time what we would regard as a leak looks ok to instruments. So, looking at memory and numbers of allocated instances is a far better guide to finding where things are not being dealloc'd.
Hard to say without any code, but it looks like you have a retain cycle somewhere.
Try to add a dealloc method to the view controllers and make sure that you enter it whenever the view controller disappears.
You say that you make a new request every 30 seconds. If you use a timer with the view controller as a target, the timer has a strong reference to the view controller and vice versa. You have to invalidate the timer when your view controller disappears.
In developing my current app, I ran into some issues that I eventually traced back to a low memory warning. Part of the low memory is coming from my (liberal) use of UIWebViews, which are apparently consuming a lot of memory.
I didn't think this would be an issue, since a view that isn't currently visible should just vanish when the low memory warning is thrown, unfortunately it turns out that anything connected to the UITabBarController remains in the heirarchy and doesn't release. By manually releasing (and then recreating in viewWillAppear) the views, I make things work decently. But it doesn't completely solve the memory warning issue.
So what I need to do is manually release the view -- and the large amount of memory that winds up connected to it -- and then restore it. Since I don't want to build it programmatically (that's what IB is for!), I need to somehow reload it from storyboard.
Or, alternatively, I'm being an idiot and there's something really obvious to make my life easy.
After more experimentation, it turns out that on the one hand, my understanding of view life cycles was slightly flawed, and on the other my experiments were tainted by having accidentally let zombie objects on.
Views will, in fact, unload their contents in a low memory condition and reload them later -- that's part of what 'viewDidLoad' and 'viewDidUnload' are designed for! Putting init code in them, as some tutorials I read did, was a major error. That init code should go in the designated initializer -- even if that can be annoying to figure out which initializer is designated.
In my app I see terrible performance when I add some custom components to a UIImageView. It's most likely the aforementioned custom components and they will need to be improved upon, but I'd like to be able to measure said improvements down the road. I'd also like to see how many times the UIImageView is drawn during the animation of a particular view.
One strategy that I've kicked around is subclassing UIImageView (only for the purpose of benchmarking) and having overridden 'draw' methods in my subclass log something and then call the super class's method.
This would be fine, save for drawRect won't be called for subclasses of UIImageView. Are there 'drawing' methods for UIImageView that I could override in this manner?
In theory, I could accomplish something similar by substituting a subclass of UIImageView with a subclass of UIView, but this will become a bit more invasive and I'd only like to do this as a last resort.
Finally, am I down a rabbit trail and there's a really obvious solution (or tool) staring me in the face? I know Instruments can provide some profiling in terms of frame rates in this area, but I don't see a solution to my problem with my limited knowledge of the tool.
Use Instruments.
It's made for these things. You even said it yourself.
The "Instruments User Guide" is a good place to start if you've never used it before.
Learning how to use instruments is time well spent. You will always have use for it when performance tuning your app, looking for memory leaks, etc.
If you really are determined to know the execution time of a method then you could have a look at DTrace. It's very powerful but a much harder than Instruments. You can also use it to build your custom tools in Instruments.
So I installed my app on my ipad and it crashes due to a memory issue. I figured this was because I'm using really big image files so I went back and reduced them all and essentially cut out about 75% of their size by resizing them and then using PNGCrush.
Now, as for running the program, if I have a background image for each of my 4 individual tabs, would it save memory if I were to set the images to Null every time I switch tabs or should I leave them set? I have one page which has a couple dozen images on it as they act as buttons and from what I'm hearing it sounds like I should clear them all when I'm not viewing that page. Is that correct?
Right now when I boot up, I load all of the images for everything in the app in a sort of: "load it now and be done with it" mentality, though from what I've been reading that causes memory issues as there isn't much memory to use. Does this mean every time I switch tabs or views I want to clear all the images from the ones that aren't visible and then reload them when we go back to them? Would this cause an increase in performance? Or at least prevent crashes? My program works in the simulator but when I run it on my ipad it just explodes =/
Thanks!
EDIT: I'm using Monotouch BTW hence everything is in C#
UIImage BG = UIImage.FromFile("Images/Makes/explosion.png");
UIImage basic = UIImage.FromFile("Images/Models/camaro.png");
UIImage advance = UIImage.FromFile("Images/search.png");
AdvancedSearchButton.SetBackgroundImage(advance, UIControlState.Normal);
ImageSearchButton.SetBackgroundImage(basic, UIControlState.Normal);
MainBG.Image = BG;
BG.Dispose();
basic.Dispose();
advance.Dispose();
Now I know in regular C# dispose() doesn't actually "free" memory, but I read something that says that it gets converted to a "release" when it compiles over to obj-c so that would essentially be freeing those objects.
Also, I'm wondering if I would need to dispose() of the individual buttons and the image after I'm no longer viewing them. I was just setting the image to NULL but that gave me errors.
MainBG.Dispose();
AdvancedSearchButton.Dispose();
ImageSearchButton.Dispose();
Thanks so much for the help!
EDIT2:
So I just tried the above code and the background images and everything else are still there and appears as if nothing is actually getting cleared. Suggestions?
The iPhone does not have virtual memory and it does not have garbage collection. So once something is loaded in the memory it stays in the memory until your code explicitly releases it. If you are not using some resources, you should definitely clean them up as soon as possible.
Also, you should listen to low memory warnings from iOS, which is another opportunity for your code to do some internal clean up.
First off, lazy load your resources unless you have a justifiable reason not to. Secondly, I'm not sure how big your images are, but on large images (ones that are by nature intended for things like backgrounds, or otherwise), generally speaking, I will chop them up into chunks, and load them, again you guessed it, lazily as they're needed.
What you should do is handle your memory warnings properly. Deallocate any resources that are not absolutely critical -- i.e., items on other views in other tabs, or hidden content. You can load them again when you have to.
You should also take a look at using Instruments to find out if you leak (I'm hoping you've already done this), examine your program to see if you can persist some cached resources to disk during low memory situations, etc.