I'm debugging slow startup of an iPhone application (Xcode, Objective C++). It's a tabbar-based app with three tabs. All three tabs are loaded in a single NIB - about 20 objects total.
The first round of significant initialization takes place in the viewDidLoad handler of the first tab's view controller. However, it takes about 1 second between main() and that method's start time - about 2/3 of the total loading time. Question - what is going on during that time, and how do I investigate that (short of stepping through the disassembly)? To the best of my knowledge, there's no my code in between the two moments - the delay happens entirely in the system code.
Maybe some kind of Instrument that can give me per-function time profile?
The bundle is ~4 MB total, but I'm loading the biggest file (~3.5 MB) later than that, in the applicationDidFinishLaunching handler. Removing that file from the bundle and commenting out the relevant code does nothing for that 1-second delay.
UPDATE: there was debug interference after all. If I run it on the device while watching the console, the startup time us considerably shorter, and the proportion of delay - system code to my code - is skewed, too. But still, there's a noticeable delay between main and viewDidLoad, and it's about 50% of total loading time.
By the way, of all ways of loading a largish file from the bundle completely into memory, the fastest one was direct memory-mapping (using POSIX mmap()).
If you really are curious about what's executing during startup, and the relative times each method takes to run, you can create a custom DTrace script to track this. I describe how to do that towards the end of this article. This script will show you every method executed by your application in order from startup to the end of -applicationDidFinishLaunching:, along with the time spent in that method. You can run this script as a custom instrument in Instruments or as a standalone script (the standalone script tends to be more accurate on a system under load).
The major caveat of this approach is that it will only run in the Simulator, given the current lack of support for DTrace in the iPhone OS itself. However, you should be able to extract the order in which things are executed in your application's startup, as well as relative times that your application spends in each method. This will even show behind-the-scenes private API calls being made as your application starts, which might provide some additional clues as to what's going on.
For additional startup tuning suggestions, I'd recommend reading James Thomson's article "How To Make Your iPhone App Launch Faster".
There are two things that could be going on here. If you're debugging your app from within XCode, there's a good chance that the application is waiting at startup to attach to the GDB debugger. In my experience, that takes about a second. Try running your app without saying "Build and Go" in XCode and see if the results are any different. (Just click it from the home screen instead)
Your NIB file might also be the issue. 20 objects isn't too many, but you might consider breaking each tab into a separate NIB file if all else fails. The contents of NIB files referenced from your primary NIB file are lazily loaded, so the app will not load views for the two tabs that are invisible until they are selected. That might give you a performance boost at startup, though I don't think it could account for a full second.
Apple's got some great performance analysis tools in the iPhone SDK, but they're a bit hard to find. In the Run menu, select "Run with Performance Tool" -> "CPU Sampler." That will launch a separate application called Instruments which allows you to do all sorts of great runtime analysis. When you have the CPU instrument selected, the bottom half of the Instruments window provides a breakdown of what was taking CPU time in your app. You can double click functions to dive into them, and get a line by line breakdown of % of cycles used. It should give you more information about what specifically is causing your problem.
I'd recommend splitting up your app into three NIBS; the tab bar and the tab bar controller displayed on launch in the first, then lazily load the other two the first time the user switches to them.
I believe you can use the File >> Decompose Interface function in Interface Builder to accomplish this.
If you found your xib files are too large, I advice you build your UI with pure code.
large xib files will surely slow your startup time, and also slow your app when you first use an object in your xib.
I don't use xib in my projects, cause when somebody changed the xib in svn, you can hardly find what is changed. That's to say, xib is not going well with SVN.
Related
I'm going back through one of my old apps (my first, actually), and am trying to reduce memory usage in order to stop it from crashing on older devices (I've run it on an old device and profiled with instruments, and it is definitely memory issues that cause it to crash). Unfortunately, when I made the app, I was not very familiar with the common practices of iOS development and structured it very poorly: with one view controller, and one xib file, hiding and showing interface elements as necessary.
Now I am wondering whether it would be worth doing a complete overhaul and starting over, with multiple classes and view controllers, and whether that will reduce the insanely high amount of memory (70+MB) needed to load the app.
Also, would it work if I just emptied out the .xib file and loaded all the interface elements programmatically (and continued using one .xib file)?
It's hard to know how much it will help without knowing what's really going on in your app. Here's some general tips to help you out though:
Split out your view controllers so you have one view controller per view. There are cases where a view controller should actually control multiple views (either for memory efficiency, performance, etc), but use this as a starting point.
Don't put all of your objects in a single XIB. Split it out so you have one XIB per view controller and let iOS load your XIB elements when needed.
Creating interface elements programmatically isn't going to help with memory usage.
Watch what you cache and only keep things in memory if there's a clear performance advantage.
If you decide to rewrite your app, be sure to profile it often using Instruments to measure your progress.
So I recently made some changes to one of my tableviews and I noticed that when the cells are being reloaded (coming back onto the screen one way or another) there is like a quarter to half second lag. I decided I'd use xcode 4's nice built in profiler. What I found is that during these spikes, most of the time running is being spent in gzopen and png_read_filter_row
I traced these functions in the call tree viwer all the way back to main, and it is never in any of my real code. The only questionable thing I am doing is small image files (1 per cell) each time cellForRowAtIndexPath is called.
I guess my question is this:
Is the file i/o that slow so that I should switch to caching these images in memory rather than on the file system?
How can I figure out what exactly it is thats slowing down my application so much using the profiling tool?
Thanks!
Can you load the images asynchronously - show a spinner where the image goes and fire off a background thread to display the image. This is a common solution to the "thumbnail image in a table row" problem.
I think you already have used the profiling tool to track down the problem: loading images. Admittedly, I am no expert on the profiler, but I think you know what you need to know. So implement your table a) without images b) with images loaded from files c) with images loaded asynchrously and stick with the fastest one. (I'm not trying to be glib, I'm just highly prejudiced toward getting the code out the door.)
Hope this helps.
-Mike
When I launch the app on my 3GS it sits on the Default.png for 4-5 seconds. I'm not sure what it is doing during this time. I placed NSLog timing statements at the top of main and didFinishLaunchingWithOptions. The NSLog statement from main does not print to the console until the moment that Default.png goes away, and the entire process from the top of main to the bottom of didFinishLaunchingWithOptions only takes 1 second.
So, what is my app doing before it starts main, and what can I do to speed that time up?
Don't start from Xcode with a debugger, that takes a lot of time. You will see that your app starts much faster when you launch it via the icon on your homescreen.
I suggest you look at your plist file and xib files (not 100% sure if root view gets loaded before or after main, but worth a shot). Also, how big is that png file? Try launching without it and see how long it takes.
Does your application do this even when there are no other programs resident in memory? The reason that I ask: since you have observed that the delay appears to happen prior to entering main(), then it is possible that iOS believes that more memory is needed in order to run your program. If there are other apps in the Suspended state, then iOS could be busy waking those apps up momentarily in order to invoke didReceiveMemoryWarning on their view controllers, and perhaps ultimately tell them to go away by calling their app delegate's applicationWillTerminate:. Perhaps this is what is taking time.
One easy test you could perform would be to completely reboot your phone and then launch your app a few times without running anything else first. After the first invokation of your app, I would expect it to start quickly (unless your app, itself, allocates a lot of memory!).
If you didn't want to reboot your phone, you could manually remove all of the apps from your multi-tasking switcher by closing each one by touching the red minus signs that you can bring up using touch-and-hold. Then run your app and see if you are still seeing the 4-to-5 second delay.
I was wondering if there is a difference between using .xib files for GUI design and doing this programmatically.
As it is a compiler I would assume that there is no relevant time lost.
Am I wrong?
(Note: Tapping this out on my phone, so I apologize ahead of time for any weird formatting or grammar - if there are issues, I'll fix them when I'm back at my laptop.)
I've done some quick, dirty, and extremely informal tests to check this out for myself, and here's what I found (note that the app I built for the tests was just scratch and not necessarily representative of a "real" app):
Startup time was faster when when the initial screen was a nib
For all subsequent screens, performance increased when coding the UI by hand
It's odd at first, but when you think about it, maybe it isn't really all that strange.
The startup issue confuses me, but I assume it's because Apple, being Apple and being obsessed with startup times (in a good way, of course), just optimized the phone's unarchiver in such a way that loading from an archive (nib) can be faster than coding by hand.
That said, most people write apps that aren't going to be significantly affected by any differences. My (again: quick and dirty) tests showed that, from a cold start (you haven't run the app yet or in a while), the nib-based app consistently loaded its initial screen about twice as fast as the hand-coded version. While that sounds like a big deal, we're talking just a few milliseconds. That difference will be imperceptible to users. For a warm start (you've already opened and closed the app), the differences for startup time were much smaller.
For this reason, I like to use nibs for laying out the foundation of an app: any top-level navigation (tab controllers, nav controllers, etc.), and then code the rest of the UI by hand.
Plus, because the iPhone UI is so specific to, well, the iPhone (surprise!), coding UIs by hand isn't difficult the way it is when writing desktop apps. You use the same UI components over and over - once you've got that down, whipping up a UI in code is easy. You don't have eight-billion widgets to choose from as you would developing a Windows/OS X/whatever application. The iPhone's consistency makes it the easiest platform I've developed against in ages when it comes to hand coding UIs.
I've also found that NSCoding (which is what I use for persisting state across app runs) is much easier to work with when I've hand-coded a UI. I've run into problems where a nib-based screen wouldn't properly archive because of UIImage instances. UIImage (at least the last time I checked) doesn't conform to NSCoding, so the archive process dies (and a rather unpleasant death it is). I used UIImage as an example here, but anything the archiver tries to store that doesn't conform to NSCoding is going to foul up the process, so that's something to think about.
Another time I always code UIs by hand is whenever I'm using a dynamic table. If I'm creating a static table - one whose cells will basically never change - nibs are fine. For any other kind of table, and especially those that have, say, thumbnails and other resource-intensive bits, the control I get when coding by hand makes it possible to get performance you aren't going to get with nib-based table cells. For that, you do have to skip CocoaTouch and work directly with CoreGraphics, but the performance improvements you can make are worth every last line of code you have to write. For examples of table performance from projects I've worked on, see the Barnes and Noble Store (not the ebook reader) and Style.com. We built a framework for those (and other) apps, and the secret to the smooth table scrolling is that we never once used cells loaded from nibs (it's more complex than that, but skipping nibs was the first step to getting the performance you'll see in those apps).
Generally speaking, possibly the most important thing to consider when using nibs is that you need to break your UI up across files. That is, don't stick your app's entire UI into a single nib. When a nib is being loaded, it's the whole thing - there might be a view in the nib your users will rarely, if ever, see, and those get loaded just like everything else, sucking up resources for no reason. If you don't use separate nibs for each of your app's screens, it's easy to run into memory and performance issues.
To further clarify: if you have an app with five view controllers, stick each controller in its own nib. You don't want to load anything until its needed. There are exceptions to this, but that's simply how coding is - given enough time, you'll find a reason to do something "the wrong way," but the a-nib-for-each-screen approach is the way you ought to be doing it unless you have a good reason not to.
I'll leave it there - I hope it helps a little.
Just remember:
My informal mucking around showed that startup was faster with a nib (as long as you keep the nib as simple as possible, keeping only what you need in it).
After startup, performance seemed to improve for hand-coded UIs.
If done correctly, and if you aren't writing a game or something, nibs shouldn't result in perceptible performance issues.
In my experience, tables are different - they're one place I will rarely use nibs.
If you're using NSCoding for persisting app state, nibs can be problematic, and any workarounds probably aren't worth the effort since coding iPhone UIs by hand is relatively easy.
Keep your nibs as simple as possible - I can't say this enough. Wherever possible, create a nib for each screen of your app rather than stuffing your entire app's UI into a single nib.
Ok. Stopping for real this time.
Hope this helps :)
Very little. There are some exceptions. For example, if you use a xib to load the image that goes into a UITableViewCell, then that could be a problem since UITableViews with many cells are sensitive to loading times. However, for all intents and purposes, there should be no noticeable performance hit.
The information in the xib does have to be decoded at runtime and loaded into memory, which is not as fast as just creating UI elements programmatically and directly.
Beware premature optimization, especially when it involves writing a great deal more code than you need to.
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.