How to Use Instruments in Xcode-(轉載)
This is a blog post by iOS Tutorial Team member Matt Galloway, founder of SwipeStack, a mobile development team based in London, UK. You can also find me on Google+.
At this point in your iOS development career, you’ve probably written an app or two, and you are no doubt wondering what you can do to make your apps even better.
Besides improving your app by adding features, there is one thing that all good app developers should do… instrument their code!
This tutorial will show you how to use the most important features of the tool called Instruments that ships with Xcode. It allows you to check your code for performance issues, memory leaks, or other problems.
In this tutorial you’re going to learn:
- How to detect and fix memory management issues in your code using the allocations and leaks instruments, and
- How to determine hot-spots in your code using the time profiler instrument and how to make your code more efficient.
Note: This tutorial assumes that you are competent in Objective-C and
iOS programming. If you are a complete beginner to iOS programming, you may wish to check out some of the other tutorials on this site. This tutorial makes use of a storyboard, so make sure you’re familiar with the concept; a good place to start is with
This tutorial will be using Xcode 4.5, so make sure you’re fully updated to the latest version, which is available through the Mac App Store.
All set? Get ready to dive into the fascinating world of Instruments! :]
Getting Started
For this tutorial you won’t go through the process of creating an application from scratch; instead, a sample project has been provided for you. Your task is to go through the application and improve it using Instruments as your guide — very similar to how you would go about optimizing your own apps!
Build and run the app, perform a search, click the result, and you’ll see something like the following:
Browse through the application and check out the basic functions. As you can see, the core feature of the app is to search and display photos on Flickr. There is a search bar at the top of the app, and when you perform a search, a new row of results appear in the table.
This new row in the table displays the search term, and the number of results found in parentheses. If you tap on a cell, the search results expand and present you with another table, displaying the image titles along with preview images.
If you tap on one of the preview results, the app takes you to a full screen view of the image. From that view, you can then rotate the image if desired.
So far so good! :] You can see that the app works as designed. You might be tempted to think that once the UI looks great the app is ready for store submission. However, you’re about to see the value that using Instruments can add to your app.
The remainder of this tutorial will show you how to find and fix the issues that still exist in the app. You’ll see how Instruments can make debugging problems a whole lot easier ! :]
Time for Profiling
Lots of developers start out with a vague idea that their app should go fast – and it’s a worthy aim. Then they read about something called “premature optimisation” and wonder how this terrible thing that the greybeard programmers frown at might be avoided. In the worst case, the novice developers forget about optimisation altogether!
To some extent, you can leave optimisation out of your app development process; only ten years ago, mobile devices were incredibly limited, and even the use of floating point numbers was forbidden because it made code size larger and calculations move at glacial speed.
Now, you hold an incredible amount of power in your pocket, complete with 3D hardware good enough to beat the best desktop hardware of not so long ago. But you can’t always depend on hardware and processor speed to gloss over the inefficient bits in your app.
So what is “profiling”, anyway? Profiling is a means of measuring. The output of a profiling session provides insight into which parts of your code are used most often; in turn, that tells you which parts of the code you should try to improve.
You can spend a week fine-tuning an interesting algorithm, but if that code only occupies 0.5% of total execution time, nobody will ever notice the difference, no matter how much you improved it. If instead you spent the effort optimising the loop where your program spends 90% of its time, and made only a 10% improvement, chances are your update will attract five star reviews because it will feel so much faster!
The first lesson of optimisation is: find the right places to do it! :]
Premature optimisation, you will have guessed by now, is spending time optimising the bits that really don’t matter in the end.
The first instrument you’ll look at is the “Time Profiler”. At measured intervals, the execution of the program is halted, and a stack trace is performed on each running thread. Think of it as pressing the pause button in Xcode’s debugger.
Here’s a sneak preview of the Time Profiler:

This screen displays the call stack of each thread. Each level, or frame, as it is called, is a different method the program’s execution path has followed to arrive at the point where the CPU is currently executing the code – that is, frame 0.
The time spent in each method can then be determined from the number of times the profiler is stopped in each method.
For instance, if 100 samples are done at 1 millisecond intervals, and a particular method is found to be at the top of the stack in 10 samples, then you can deduce that approximately 10% of the total execution time — 10 milliseconds — was spent in that method. It’s a fairly crude approximation, but it works!
So without any further ado, time to get instrumenting!
From Xcode’s menu bar, select ProductProfile, or press ⌘I. This will build the app and launch Instruments. You will be greeted with a selection window that looks like this:
These are all different templates that come with Instruments.
Select the Time Profiler instrument and click Profile. This will launch the iOS simulator and start the app. You may be asked for your password to authorise Instruments to analyse other processes — fear not, it’s safe to provide here! :]
In the Instruments window, you can see the time counting up, and a little arrow moving from left to right above the graph in the center of the screen. This indicates that the app is running.
Now, start using the app. Search for some images, and drill down into one or more of the search results. You have probably noticed that going into a search result is tediously slow, and scrolling through a list of search results is also incredibly annoying – it’s a terribly clunky app!
Well, you’re in luck, for you’re about to embark on fixing it! However, you’re first going to get a quick run down on what you’re looking at in Instruments.
First, make sure the view selector in the toolbar has all three options selected, like so:
That will ensure that all panels are open. Now study the screenshot below and the explanation of each section beneath it:
- These are the recording controls. The middle red button will stop & start the app currently being profiled when it is clicked. This is actually stopping and starting the app — not pausing it.
- This is the run timer and run navigator. The timer counts how long the app being profiled has been running. The arrows move between runs. If you stop and then restart the app using the recording controls, that would start a new run. The display would then show “Run 2 of 2”, but you could get back to the data of the first run by first stopping your current run, then pressing the left arrow to go back.
- This is called a track. In the case of the time profiler template you selected, there’s just one instrument so there’s just one track. You’ll learn more about the specifics of the graph shown here later in the tutorial.
- This is the extended detail panel. In the case of the time profiler instrument, it’s used to show stack traces, as that is what Instruments is recording.
-
This is the detail panel. It shows the main information about the particular instrument you’re using. In this case, it’s showing the methods which are “hottest” — that is, the ones that have used up the most CPU time.
If you click on the bar at the top which says “Call Tree” (the left hand one) and select “Sample List”, then you are presented with a different view of the data. This view is showing every single sample. Click on a few samples, and you’ll see the captured stack trace appear in the extended detail panel.
- This is the options panel. You’ll be learning more about these options shortly.
Now onto fixing the clunky UI! :]
Drilling Deep
Perform an image search, and drill into the results. I personally like searching for “dog”, but choose whatever you wish – you might be one of those cat people! :]
Now, scroll up and down the list a few times so that you’ve got a good amount of data in the time profiler. You should notice the numbers in the middle of the screen changing and the graph filling in; this tells you that CPU cycles are being used.
You really wouldn’t expect any UI to be as clunky as this; no table view is ready to ship until it scrolls like butter! To help pinpoint the problem, you need to set some options on the time profile perspective.
Under the Call Tree section on the left, select Separate by Thread, Invert Call Tree, Hide System Libraries and Show Obj-C Only. It will look like this:
Here’s what each option is doing to the data displayed in the table to the right:
- Separate by Thread: Each thread should be considered separately. This enables you to understand which threads are responsible for the greatest amount of CPU use.
- Invert Call Tree: With this option, the stack trace is considered from top to bottom. This means that you will see the methods in the table that would have been in frame 0 when the sample was taken. This is usually what you want, as you want to see the deepest methods where the CPU is spending its time.
- Hide Missing Symbols: If the dSYM file cannot be found for your app or a system framework, then instead of seeing method names (symbols) in the table, you’ll just see hex values. These correspond to the address of the instruction within the binary code. If this option is selected, then these are hidden, and only fully resolved symbols are displayed. This helps to declutter the data presented.
- Hide System Libraries: When this option is selected, only symbols from your own app are displayed. It’s often useful to select this option, since usually you only care about where the CPU is spending time in your own code – you can’t do much about how much CPU the system libraries are using!
- Show Obj-C Only: If this is selected, then only Objective-C methods are displayed, rather than any C or C++ functions. There are none in your program, but if you were looking at an OpenGL app, it might have some C++, for example.
- Flatten Recursion: This option treats recursive functions (ones which call themselves) as one entry in each stack trace, rather than multiple.
- Top Functions: Enabling this makes Instruments consider the total time spent in a function as the sum of the time directly within that function, as well as the time spent in functions called by that function. So if function A calls B, then A’s time is reported as the time spent in A PLUS the time spent in B. This can be really useful, as it lets you pick the largest time figure each time you descend into the call stack, zeroing in on your most time-consuming methods.
Although some values may be slightly different, the order of the entries should be similar to the table below once you have enabled the options above:
Well, that certainly doesn’t look too good. The vast majority of time is spent in the table cell that sets the photo. That shouldn’t come as too much of a shock to you, as the table scrolling was the clunkiest part of the UI, and that’s when the table cells are constantly being updated.
To find out more about what’s going on within that method, double click on the row. Doing so will bring up the following view:
Well that’s interesting, isn’t it! Almost three-quarters of the time spent in the setPhoto: method is spent creating the image data for the photo!
Now you can see what the problem is. NSData’s dataWithContentsOfURL blocks (that is, does not return) until the data has been downloaded. Since this request goes out to the internet to grab the data, each call could take up to a few seconds to return. This method is run on the main thread, and therefore the entire UI is blocked from updating whilst the image data is downloaded.
To solve this, a class has been provided called ImageCache which allows asynchronous downloading of images on a background thread. The code exists in the PhotoCell class.
You could now switch to Xcode and manually find the file, but Instruments has a handy “Open in Xcode” button right in front of your eyes. Locate it in the panel just above the code and click it:
There you go! Xcode opens up at exactly the right place. Boom!
Now, comment out the two lines which grab the NSData and set the image, and uncomment the block of code below. The setPhoto method will then look like this:
|
Re-run the app in Instruments by pressing ProductProfile (or ⌘I – remember, those shortcuts will really save you some time).
Notice that this time you are not asked for which instrument to use. This is because you still have a window open for this app, and Instruments assumes you want to run again with the same options.
Perform a few more searches, and notice that this time the UI is not quite so clunky! The images now load asynchronously and are cached in the background, so once they’ve been downloaded once they do not have to be downloaded again.
Looks great! Is it time to ship it? Not yet! :]
Allocations, Allocations, Allocations
The next instrument covered in this tutorial is the allocations instrument. This gives you detailed information about all the objects that are being created and the memory that backs them; it also shows you retained counts of each object.
The easiest way to start afresh with a new instruments profile is to just close Instruments and start again. Close Instruments, go back to Xcode and select ProductProfile again. Then select Allocations from the picker and click Profile.
Instruments will open once again and you’ll be greeted with the following:

This time you’ll notice two tracks. One is called Allocations, and one is called VM
Tracker. The Allocations track will be discussed in detail in this tutorial; the VM tracker is also very useful, but is a bit more complicated.
So what bug are you going to track down next? :]
There’s something hidden in the project that you probably don’t know is there. You’ve likely heard about memory leaks. But what you may not know is that there are actually two kinds of leaks.
The first is the true memory leak, where an object has not yet been deallocated, but is no longer referenced by anything. Therefore the memory can never be re-used.
The second kind of leak is a bit more tricky. It’s called “unbounded memory growth”. This happens where memory continues to be allocated and is never given a chance to be deallocated.
If this continues forever, then at some point the system’s memory will be filled and you’ll have a big memory problem on your hands. In iOS this means that the app will be killed by the system watch dog. This will not lead your app to five-star ratings! :]
Set up a scenario where you can detect unbounded memory growth. First, make 10 different searches in the app (but do not drill into the results yet). Make sure the searches have some results! Now let the app settle a bit by waiting a few seconds.
You should have noticed that the graph in the allocations track has been rising. This is telling you that memory is being allocated. It’s this feature that will guide you to finding unbounded memory growth.
What you’re going to perform is a “heap shot analysis”. To do this, press the button called “Mark Heap”. You’ll find the button on the left side of the detail panel:

Press it and you will see a red flag appear in the track, like so:

The purpose of heap shot analysis is to perform an action multiple times, and see if memory is growing in an unbounded fashion. Drill into a search, wait a few seconds for the images to load, and then go back to the main page. Then mark the heap again. Do this
repeatedly for different searches.
After a drilling into a few searches, Instruments will look like this:

At this point, you should be getting suspicious. Notice how the blue graph is going up with each search that you drill into. If you continue this for all 10 searches, you’ll end up with a graph that looks like this:

Well, that certainly isn’t good. But wait, what about memory warnings? You know about those, right? Memory warnings are iOS’s way of telling an app that things are getting tight in the memory department, and you need to clear out some memory.
It’s possible that this growth is not just due to your app; it could be something in the depths of UIKit that’s holding onto memory. Give the system frameworks and your app a chance to clear their memory first before pointing a finger at either one.
Simulate a memory warning by selecting HardwareSimulate Memory Warning in the iOS simulator’s menu bar. You’ll notice that memory usage dips a little, but certainly not back to where it should be. So there’s still unbounded memory growth happening somewhere.
The reason for doing a heap shot after each iteration of drilling into a search is that you can see what memory has been allocated between each shot. Take a look in the detail panel and you’ll see a bunch of heap shots.
Hit Me With Your Best Shot
The first is the baseline shot. Open that up you’ll see all the objects that were allocated and still resident at the time that heap shot was taken. Subsequent heap shots will contain just the objects between the previous heap shot and the current one.
Look at the “Heap Growth” column and you’ll see that there is definitely growth occurring somewhere. Open up one of the heap shots and you’ll see this:

Wow, that’s a lot of objects! Where do you start?
The best thing to do is to look through the list for the classes that you use in your app directly. In this case, HTTPHeaderDict, CGRegion, CGPath, CFNumber, etc can all be ignored for now.
However, the one that stands out is UIImage, as that’s certainly something that is dealt with in your app. Click on the arrow on the left of UIImage to display the full list. Select one and look at the extended detail panel:
This shows you a stack trace at the point when this specific UIImage object was created. The parts of the stack trace in grey are in system libraries; the parts in black are in your app’s code. To get more context for this trace, double click on the only black frame that is in a method of the ImageCache class. This will take you to the code for that method, which looks like this:
|
Instruments is pretty useful, but it can help you no further in this case! You’re now going to have to work through the code yourself in order to understand what’s going on.
Take a look through the method above, and you’ll see it calling a method called setImage:forKey:. This method caches an image in case it is used again later on in the app. Ah! Well that certainly sounds like it could be a problem! :]
Take a look at the implementation of that method:
相關推薦
How to Use Instruments in Xcode-(轉載)
This is a blog post by iOS Tutorial Team member Matt Galloway, founder of SwipeStack, a mobile development team based in London, UK. Y
Why (and how) to use eslint in your project
Why (and how) to use eslint in your projectThis story was written by Sam Roberts, a Senior Software Engineer at IBM Canada. It was first published in IBM d
How to use AI in the insurance value chain: customer service and policy administration
How do you approach customer service and policy administration within your organization? In this blog post, I'll demonstrate how artificial intelligence (A
How to use AI in a small business
If you are a small business owner, you may wonder if it is possible to implement AI in your business; you may even feel very challenged by the idea. There
How to use Git in a secure way
How to use Git in a secure wayWe live in a world where it is hard not to know Git, the most popular Distributed Version Control System (DVCS). Free and ope
How to use DeepLab in TensorFlow for object segmentation using Deep Learning
How to use DeepLab in TensorFlow for object segmentation using Deep LearningModifying the DeepLab code to train on your own dataset for object segmentation
how to use composer in fiddler
aix cti request com connect req cnblogs 表示 技術分享 https://www.cnblogs.com/youxin/p/3570310.html http://docs.telerik.com/fiddler/generate-t
how to use Inspector in fiddler
date perm alt com ons blog ima ddl content 打開fiddler之後,會自動捕獲本機的http請求,以列表的形式顯示在左側 雙擊左側列表中的某一個request,右側會自動切換到Inspectors窗口。 右側上半部分是reque
How to Use Loaders in Android
With the introduction of Honeycomb Loaders became the preferred way to access data of databases or content providers.
How to use VirtualBox in Terminal / Command line
How to manage VirtualBox in command line or terminal. VBoxManage is the command which is used to manage VirtualBox in commandline.
How to use *args and **kwargs in Python
這篇文章寫的滿好的耶,結論: 1星= array, 2星=dictionary. 1星範例: def test_var_args(farg, *args): print "formal arg:", farg for arg in args: print "an
How To Use Retrofit Library In Your Android App
Retrofit library is a Type-safe REST client for android and Java, courtesy of Square Inc. Most modern android apps make HTTP requests to some remote s
How To Use Simple Factory Design Pattern In Java
Simple Factory Design Pattern is one of the many design patterns – best practices on how to solve common problems. Design Patterns were made popular by
how to use “request” object within a function in jsp
request is accessible inside the scriptlet expressions, because it’s an argument of the method in which these expressions are evaluated (_jspService). But
How to use APIs with Pandas and store the results in Redshift
How to use APIs with Pandas and store the results in RedshiftHere is an easy tutorial to help understand how you can use Pandas to get data from a RESTFUL
How to Use IoT Datasets in #AI Applications
Recently, google launched a Dataset search – which is a great resource to find Datasets. In this post, I list some IoT datasets which can be used for Machi
10 Examples of How to Use Statistical Methods in a Machine Learning Project
Tweet Share Share Google Plus Statistics and machine learning are two very closely related field
How to Use Metrics for Deep Learning with Keras in Python
Tweet Share Share Google Plus The Keras library provides a way to calculate and report on a suit
How to Use Parametric Statistical Significance Tests in Python
Tweet Share Share Google Plus Parametric statistical methods often mean those methods that assum