Essentials • 55:37
Performance optimization is critical for iPhone applications. Learn the best practices for using memory efficiently, optimizing drawing and scrolling operations, and minimizing power consumption for iPhone applications. Discover tips and tricks for using Mac OS X performance tools such as Shark and Instruments to diagnose suboptimal behavior quickly, and learn about built-in solutions on iPhone that maximize available resources.
Speakers: Dave Myszewski, Peter Handel
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon. We have a lot to talk about today. Made my first mistake. I'm David Mishefsky. I've been working on iPhone performance for a little over two years, where I've concentrated on high-level application and framework performance. So I've done things like optimize scrolling and SMS transcripts, large contacts lists, and optimized a lot of code for performance over the last couple of years. And we have a lot of great topics to talk about. And so let's give you a quick overview. When we talk about performance, we usually think about three things.
And that's CPU slash GPU usage, memory, and of course, power. So to cover all of these topics, we're going to divide it into five sections. The first is drawing and scrolling, where we have all sorts of wonderful graphics and smooth animations on iPhone apps. So we'll learn how to optimize applications for those graphically rich applications. And then we'll talk about performance. And then we'll talk about performance. And then we'll talk about performance.
And then we'll talk about performance. Application launch, which is absolutely critical for iPhone, and a little bit different than Mac OS X because of the different use cases that we have on iPhone. Memory usage, which is absolutely critical for iPhone applications because we have a limited amount of memory, and we don't have a swap file on iPhone. So we'll tell you how to deal with that limitation. Files and data.
And there are some nice little optimizations that we can make, particularly with large data files. And finally, because this is a mobile device that people carry around with them every day, and it's their connection to the outside world, it is critical that our battery life is very, very good on this device. So we'll tell you some things that you can do in your applications to ensure that users will experience good battery life.
So the first thing that you notice about iPhone is that it's not quite a Mac in terms of the hardware characteristics. If we compare our slowest Mac Mini that we shipped today to the iPhone and iPod Touch, there's really no contest in terms of speed. CPU is much, much greater. The RAM, of course, is very, very high in any of the Macs that we ship, and it's backed by the large swap file that you can put on these wonderful hard drives. There's no L2 cache on iPhone or iPhone X.
And of course, for networking, we have three different types of connection. We have Wi-Fi, which is very, very high bandwidth, low latency, 3G, which is high bandwidth and high latency, and Edge, which is low bandwidth and high latency. So in order to put this great Mac OS X software into a small device like iPhone, we need to do a few different things. And you will find that as you're developing your applications, that you're going to need to have a lot of experience with the Mac OS X. Thank you.
The simulator is a great tool for rapid application development and for testing your applications against frameworks, but the performance that you experience on the device because of those different hardware characteristics is actually much, much different on the iPhone. So to demonstrate the importance of profiling your applications on the iPhone and periodically running your devices on the iPhone hardware itself, we have Peter Handel, who is on the iPhone power team. And so, Peter, if you'll give the demo. Thank you.
Hi, everyone. My name is Peter Handel. I'm an iPhone power engineer. Been doing that for almost two years now. As Dave mentioned, it's really important to check the performance of your application, not just in the simulator, but also on the device. Let's go ahead and have an example of that.
So here we are in Xcode. We have a simple little movies application here. Now I'm going to go ahead and say, let's go ahead and run this on the simulator and take a look at it. Well, here we have title of movies, the actors, who's in it, a little synopsis of it. And when we scroll it, it looks pretty good, right? I mean, this is pretty smooth scrolling.
Now, let's go ahead and select our device to be the target. Now what it's doing right now, we're going to recompile this for the phone that I have sitting right here. It's going to go ahead and ship that over and run it on here. So let's take a look. So it's the exact same application as we had in the simulator here. However, when we scroll it, it's pretty chunky.
Can we get the iPhone here? There we go. Great. So as we see, it's pretty chunky. Honest. And that's an example of why it's really important to check the performance on the device, not just on the simulator. Dave? So that was a great example of why when you are designing and implementing your applications, you need to periodically run them on the device to ensure that your application has great performance and will be a really, really good first experience for the users.
And to optimize for the iPhone, we have some great drawing technologies. We, of course, have all the ones that you're used to on Mac OS X, Core Animation, our Quartz 2D drawing system. And for your wonderful games, we have the OpenGL ES and, of course, the UI Kit graphics, which gives you all of your standard widgets and the ability to draw your own customized views for whatever your drawing purposes are.
So the first thing is, if we provide a widget for you, then please use this. Please use the widget for the drawing. A great example of this is UIImageView which is very, very nicely optimized to get your image contents to the hardware as quickly as possible without using more memory.
So UIImageView provides a great way for you to display images on the screen and of course if you want to add a label to this picture, UILabel is also nicely optimized and takes care of a lot of things for you. So if we have a built-in widget, then please use them.
And the same goes for animation. We have a wonderful, wonderful animation system on our iPhones, Core Animation, and we provide built-in capabilities to do things like alpha fades, moving views across the screen, and all sorts of other wonderful animations. So if you use the UIImageView animations or Core Animation directly, you'll get some really great performance because it's heavily optimized for our hardware.
But a lot of times you are going to be drawing views yourself. So when you draw views yourself, there are several things you need to take into consideration. The first one is the same thing that we mentioned on Mac OS X, which is mark your views as opaque. On iPhone and iPod Touch, this optimization is even more important than it is on Mac OS X because of our limited processing and GPU capabilities.
When you mark views as opaque, the entire compositing system and the hardware has to do a lot less work in order to get the content that you are drawing all the way through the hardware and onto the screen so that the user can see it. This happens in particular in scrolling. So in the demo that Peter just showed you, many of the views that were on the screen were actually translucent, causing the hardware to do a lot more work and giving us the chunky scrolling that you saw in the demo.
So always mark your views as opaque. The second optimization is, again, another one that we have on Mac OS X, which is draw as little as you can. If you have, for instance, a screen region where your entire view may not be updated, but only one half of it will be, then tell UIKit to, by using the set needs display and rect method, to dirty one particular region so that when you have to draw, you can check that rectangle in draw rect and only redisplay that one portion of the screen.
So that is one optimization that will allow our hardware to have to do a little bit less work and make the user experience a little bit better for your users. There are very, very, very few drawing operations that could actually be done before the time that it takes to actually just check a rectangle for intersection. So always use set needs display and rect when it applies to your custom views.
And the next optimization is to cache any drawing objects that you need to redisplay really, really quickly. Now, this doesn't go for every image in your application, but there may be times during your application where you might decide it's a little bit better if we already had this object in memory. We do have a little bit of memory on the device, so we can use it. But when you make this sort of optimization, always be prepared to release those objects when you have low memory conditions, and we'll talk a lot about that later on in this talk.
The next optimization is the best sort of optimization. It's the type of optimization that we give you for free, and that's using ping files. Now, we have chosen the ping format on iPhone because we have some very, very good performance changes that we've made, and we optimize our ping files at build time. They're very quick to load, and they have all the great translucency, and they have the alpha channels so that you can have the great graphics that you expect.
When you hit build in Xcode, Xcode automatically optimizes your pings and converts them to an optimized format that we can draw very, very quickly on iPhone. This means that your images will appear very, very quickly when you launch your app. So if you use ping files, you get this benefit for free.
Now, there are a few tips for OpenGL ES. This was covered in great detail earlier in the week, and there will be a lot of OpenGL people at the lab tomorrow. But for anybody who is developing games, of course, realize that OpenGL is a little bit different from OpenGL on Mac OS X.
In particular, it's a tile-based deferred renderer, and so that has some implications that if you went to the talk on Tuesday, they explained exactly what this means. It means it's very well optimized for memory, but you have to design your application a little bit differently. Textures and renderer buffers are limited to 1024 by 1024.
And, of course, we don't have any separate graphics memory. Your texture memory is shared with application memory, so it makes memory management very, very important. One main optimization that we use here is if you have layers, try not to transform them because it will give you a fairly, fairly expensive cost. It will be likely to drop frames. And, of course, some operations may not be available that are available on OS X. And there's a lot of great, great documentation on the iPhone OS programming guide.
[Transcript missing]
And then, of course, you have this poster image. That's another view, so that's three. You have the title. That's four. You have the ratings image. That's five. If you want an intern to spend a couple hours doing something, have them research the font used for the rating image. The cast, of course, that's another one. And finally, you have all of your nice description that we have. So from this randomly chosen movie, we've showed how many views that we have.
So you don't want to be creating all of those views as you scroll. That's why we have this great optimization that's super easy to use. So always, always use it. Now, there's one more optimization that's a little bit more work and only applicable in some special cases. And if you have all of that content, that's a lot of subviews.
So one thing you can do if you have a table view that is the plain style table, and it doesn't show any editing or reordering, those sorts of controls, you can actually collapse all of these views into a single view. And that actually makes core animation do a little bit less work as you are scrolling through the system. And we'll show you what that optimization looks like in a little bit.
So now that we've shown you a few things that you can do for performance, how do you figure out which one of these things that I just showed you actually applies to your app? Well, we have the absolute best set of performance tools that are available on any mobile platform. And we've had a couple of sessions on them. There's some sessions later on about these performance tools. The first one is Instruments. Now, Instruments gives you a nice suite of instruments that helps you figure out what's going wrong in your application.
So we have a sampling tool. We have an object allocation tool to track your memory usage so that when your memory is high and you don't know exactly why it's high, it will actually tell you what classes are currently in use and where they were allocated. It gives you a lot of great information. An activity monitor tool to figure out what's going on in the system. A leaks tool, because memory leaks are very, very bad for this device. And you want to never, ever have memory leaks when you submit your application to the iTunes store.
And we have a core animation tool that will show you a lot about the core animation layers, and we'll demo that in a moment, and an OpenGL tool so that you can optimize your great games. In addition to Instruments, we brought Shark over to iPhone. So Shark will give you a breakdown. For those many of you who have developed on Mac OS X before are very, very familiar with this tool.
The great thing about Shark and Instruments too is that neither of those applications forces you to recompile your application and then run them in some special programming environment. Both of them, you can take already compiled applications and just run these performance tools against them. And in the case of Shark, it will give you a time profile so that you can figure out what your program is doing at many, many points in time. And it will also have sophisticated data mining technologies that will allow you to figure out exactly what's going wrong. in your program. And we'll show you Shark in a moment as well.
So now the question is, we have all these great performance tools. Some of them apply to the simulator. Some of them apply for the phone. So which tool should you use for performance? Well, on the simulator, object alloc and leaks are the great instruments that work both on the simulator and the device. Memory allocations are often roughly comparable on the simulator and the device, as are memory leaks.
If you have a leak in your own code on Mac OS X, it's fairly likely that you have a leak on the device and vice versa. But always run it in both just to be sure. And also we have, if you went to the instruments talk earlier today, there are also the Mac OS X set of tools that allow you to do some fairly sophisticated things like detrace even in the simulator because it is just a Mac OS X app. On the device, of course, we have Shark that's available. And, of course, we have... have all the instruments too.
So the main thing that I want to get across is that things like sampling aren't quite as applicable on the Mac as they are on the device. In fact, a sample that you get from the Mac OS X may be, in fact, completely different from a sample you would get on the device.
So you should always run your sampling, your Shark, on the device and not on the simulator. We make it really, really easy for you to do this. So always run your performance tools on the device. And so now with all of those things in mind, let's actually take the app that we showed before and let's make it a lot better. So to demonstrate this, Peter is going to show us the app.
Hi again. So at the end of the last demonstration, our movies app was in pretty bad shape. You guys remember we'd scroll around on it and it was just real chunky. And that's not really the first impression that we want to leave our users with. So how do we go about finding that performance issue and then fixing it? Well, let's take a look here.
We're going to go ahead and open up Xcode again. I'll bring up our project here. And this time I'm going to go ahead and say, start with Performance tool and say Core Animation. The Core Animation instrument is a great tool for understanding what and how often we're drawing to the screen.
It's also great to help diagnose the most common issue that we see, the most common performance issue that we see, which is unnecessary blending of transparent layers. This is very computationally intensive and will lead to dropped frames when we do this. So here we have instruments. You'll notice in the top right hand corner we have a large frames per second indicator.
Since we update the screen, as Dave mentioned, 60 times per second on the device, you'll want to be as close to 60 frames per second here as you're scrolling. Next, we're going to go ahead down here under the Debug Options portion and check Color Blended Layers. What this will do is for any subviews that are transparent, it'll color them red.
Let's see what our application looks like on the device. So can we switch to the-- whoops, in here? That's pretty red, huh? So in other words, we're spending a lot of time blending all these layers together. So that's the Core Animation tool. Let's go ahead and switch back here to this. And quit this.
Next, Shark. Shark is an incredibly powerful performance analysis tool that helps you find hotspots in your code. If you've used Shark in the past, you'll find it's on the device, it's just like running it on the computer. To get a better understanding of why our movie's apps is scrolling slowly, let's take a look at this in Shark. So I'm going to go ahead and bring this up here.
Now, notice here under the sampling menu, we have an option called Network and iPhone Profiling. So we'll select that. And notice, here's our device right here. When I check that, I'm going to go ahead and tell Shark that I'd like to use this, use this phone that I have right here.
And there it is. So to debug our scrolling issue, I would launch my application, hit Start here, this button right here, scroll around a bit, hit Stop, and then take a look at the resulting profile. Now in the interest of time, I've already got that shark trace right here.
So we're in the tree top-down view. Dave, what's your favorite view? What do you like to use when you're just taking a look at an application real quick? DAVE MYERS: So usually the first time I look at an application, I look at the top-down view just to give me an idea about where time is spent in the application.
The second view, the heavy view, which is sort of a bottom-up view, lets you find if there's a particular function that's a very, very hot spot in your code. It often finds that one really, really quickly so that you'll know if you have a computationally expensive function, which one to optimize.
We're looking at the top down view here, which gives us, like Dave said, a good high level view of where our app's spending time. We can drill down and see one function call another here. So for example, we have the UI application main, which eventually calls this UI table view layout subviews, where it's decided whether or not we need to bring in a new cell as we're scrolling. So when we look at this, it looks like we're spending 22.2% of our time in this movies view controller table view cell for row index path function, which then itself calls this movie summary cell in it with frame reuse identifier.
So let's go ahead and switch to the chart view and take a look at this here. In the chart view, we have a graphical way of seeing how much time our program is running. Notice that whenever you see blue, that's our movies application running. And when you see yellow, it's that movie summary cell function that we had highlighted in the previous window. So let's zoom in here and see how long we're running for.
So looking at this, this is a pretty long time. We're running for, from here to here, we're running a little over 30 milliseconds. If we want to be at 60 frames per second in our scrolling, then we only have about 16.6 milliseconds for each frame to update our table view. So we're going to have to spend a lot less time in this table view and movie summary cell function.
So the two big problems we've found in our code so far is that, number one, we have transparent layers that don't need to be transparent, which can lead to expensive and unnecessary blending. And number two, we're spending too much time in this table view function. Let's find and fix these in our code. So to fix the transparency issue, I'm going to go ahead and do a search here for clear color.
And here it is in our code. We're setting this background color of this label to clear. So if we were to switch that, we So, oftentimes, you will select your table cells. That's what they're there for. You use it in the navigation hierarchy. And when you select a table view cell, of course, you have your content, which is in a label. And beneath it, you'll have the blue selection on iPhone.
Now, of course, conceptually, your label is basically a square with some text in it. And so, if you make that opaque, then conceptually, it seems as though when you put it on your table, you would get, when the user selects your table view cell, that you would actually have a giant, big rectangle that would look really, really ugly when you select it.
But because this is really, really common, the UI table view actually is really smart about this, and it will actually swap that label's color to clear when you make the selection. So, when you set it to white, you'll have the great scrolling performance that you have, which is identical to your table cell's background color.
And when you have selection, you'll get all of the great benefits of translucency, which is a view that looks exactly as you want it to look. So, always make sure that if you have a label that's on a white background, just set it to the white color, and you'll get your better scrolling performance.
performance with just that one line of code. So going from clear to white fixes the issue that we saw earlier in the Core Animation tool. Next, how do we speed up our usage of the table view? Let's take a look at the method that provides the cell to the table view.
And looking at this function, it looks like we're not reusing the table view. The table cells, excuse me. Reuse identifier set to nil right here. But rather, we're creating a new table row for each cell. A new table cell for each row, excuse me. This is really important. You cannot get smooth scrolling without cell reuse.
Let me repeat that. You cannot get smooth scrolling without cell reuse. So we'll go ahead and change our code here to do cell reuse. comment out this guy up here. See, we have this movie string, a summary identifier, and a string that we then pass into the reuse identifier right here.
Now, there's one more optimization that I don't have time to show you that Dave mentioned earlier, and that's the consolidation of all the layers into one layer. Depending on your application, this may or may not make a big difference. In this case, in this application, it actually ends up making a big difference. So I've got another version here on the device, on the phone, that has all three of these optimizations. So if we could switch to the device here. And when we scroll now, it's a lot smoother. Dave? Thanks, Peter.
So the first thing that I always look at every time somebody says, I have a scrolling problem. What do we need to do to make it better? I make sure that that view is opaque. So make sure you always mark your views as opaque. Draw minimally, so don't draw anything more than you need to. And for games, drawing minimally also expands to when the screen isn't actually changing, don't draw. It will reduce your battery life.
Reuse table cells, always. I tend to consider this as not so much an optimization as a requirement when you're using table views. Reuse is so important for good scrolling performance. You should always use it. And for some applications, you may want to collapse the cell layer hierarchy for, again, the plain style table when you don't support editing. And if you have something that's really, really complicated, sometimes that will be a good optimization for you.
So that's drawing and scrolling, where we took an application that was probably a free app and made it into something that maybe we could charge for. So now that was drawing and scrolling, let's talk about application launch. Now, application launch on iPhone is super, super critical. On Mac OS X, say some Hollywood director living in Hollywood is working on their Macintosh, they may have Final Cut Pro open all day and just be living in that application, and that's their job.
On iPhone, the most common user scenario is to take your iPhone out of your pocket, maybe check the weather, and then brag to all your friends about how good it is here, and then put it back in your pocket. So you really want to have a very, very fast application launch.
So when you are designing your application, both the UI and the actual implementation, consider what the user needs immediately when they launch to their app. You want to make your app launch and quit as quick as possible so that users can get what they need done very, very quickly.
So get your UI on the screen as quickly as possible, and that means don't load data until you need it. Now, UI view controller has a lot of wonderful optimizations that do all the stuff for you so that we don't actually load the view until the view appears on the screen.
And make sure that if you have a large, large list, maybe you don't want to load all 500 records. Maybe you just want to load the first 20 or 30 or some small subset. You just want to make every optimization you can make so that the application will appear on screen really, really quickly.
We've done this in basically all of our apps, but a couple of great examples are the phone. If you launch to, say, the context view, you don't really want to spend time loading all of this keyboard stuff or keypad stuff and vice versa. So this is an example of that UI view controller optimization where we only load what's on screen. And the same goes for your back-end data structures. Not only do we not load the actual views, we don't load any of the data that we do not need when you launch to this view. Amen.
Now, most of the applications on iPhone, if you just take a rundown of them, access the internet right away. YouTube, basically every other app does. And what we do in our applications, and we suggest you do too, is we try to quickly display all the user interface that we can. So we have the bottom button bar. We have our nice little segmented control at the top. And we give the user some feedback, both in the status bar with our little loading spinner and in our actual app.
And we have our little view saying that, oh, we're loading this data. So if you launch and display everything that you can, but then as you're doing the expensive network operations, provide some feedback to the user that you are actually doing something. That will make the user experience a lot better when you don't have control over how quickly those resources will load. And also keep in mind that you have different connection types on iPhone.
You could be on Edge if you're in my home state of Wyoming. You could be on 3G if you're in a lot of places in the country. Or you could be on Wi-Fi if you're in a lot of places in the country. which is your best case scenario.
So defer as much as you can and show everything that you can on application launch that doesn't require going over the network. So that's a quick summary of application launch. And now on to a very big topic, which may be new to a lot of people, and that's memory usage.
Now, memory usage is important on any computing device, but on iPhone, it's very, very, very important because the memory that you use will directly impact both the performance and the stability of your applications. In particular, as you are using more and more memory in your application, we send out memory warnings that will tell you you're reaching a high watermark in memory usage. You may want to free some memory.
If you ignore that and keep going and keep going, then eventually the system will say, hey, I'm out of memory. I can't do anything. We must quit that frontmost application. So memory usage is really, really important to optimize on your iPhone. And so let's talk a little bit about that.
So why do we have these memory warnings and maybe kill the frontmost app? Well, there's no swap file. So we have all the great virtual memory and all the other modern features of this modern OS, but there's no swap file. So that means that any application pages that you dirty, any of your data models or things like that that aren't statically loaded code or statically loaded data, you can't do anything about that.
So that means that any application pages that you dirty, any of your data models or things like that that aren't statically loaded code or statically loaded data, you can't do anything about that. So you have to stay in memory. And all of your pages that are read-only will be evicted and reloaded.
So if you're up at that threshold at the top, then your performance may degrade if you have to bring in new code. So you want to use a small amount of memory, as small amount of memory as you can at the time. Now, the one optimization that's really important for iPhone is memory mapping. And I'll talk a little about that in the files and data loading segment. But it's a technique where you can use a small amount of memory. memory for large data sets.
So of course, we have all the normal things that you are familiar with, with C and Objective-C. We manage memory with alloc init autorelease, retain release autorelease to manage reference counts. We don't have garbage collection on the phone. But of course, we have the standard C, malloc and free, C++, new and delete, all the things that you're used to. So this is the same model that you're used to on other platforms.
So we're going to talk about three different memory optimization classes. The first is static memory, which is memory that you can optimize before your code even runs. Then dynamic memory, the code that all of the memory that you use in the application. And of course, how to cover the new feature on iPhone, which is memory warnings.
So the first thing we actually do for you for free, which is we try to reduce code size. And we do this with the -mthumb compiler flag. So what is this thumb thing? Well, our ARM core actually supports two different instruction sets. One is the normal ARM 32-bit instructions and another is this subset called thumb, which is 16 bits.
And of course, if you do the math, if your code size is half the size, then that's going to give you a nice performance benefit because you won't have to read as much code to launch your app. Less code will give you less code that's being executed - sorry, a smaller code size will often equal better performance because we won't have to evict code pages as your memory grows. And so thumb is a really nice optimization and it's so important to us that we make it the default in Xcode.
So then the question becomes, if this optimization is so great, why not do it for everything all the time, and why even have a compiler flag? Well, there's one little catch to Thumb, and that's that if you have intensive floating point operations, you may notice a small performance difference.
So things like games, Thumb may not be suitable for them. But for many things like UI layouts, basically all the apps that you can think of that just do some basic UI layout, interact with UIKit, those sorts of applications, Thumb will be a great optimization, and you won't notice a performance difference.
Performance difference isn't big. If you have a really, really, really intensive floating point operation, you can actually do one neat thing, which is compile just single files for ARM and compile everything else for Thumb. So we give you a lot of control over this compiler optimization. A second one, since we are in the business of decreasing code size, one nice easy one is another checkbox, which is dead code stripping. So when your application is linked, it will try to figure out if there are any functions that are implemented but not referenced, and just eliminate those. And so that's a nice quick optimization for you.
Another couple of compiler flags for anybody who uses C++ are Objective-C exceptions and run type type identification, which is used for things like dynamic cast. So if you're using C++ code, you may consider not using either of these features because on the limited processing power that we have on iPhone, we really need all the horsepower that we can get. If you can do it by clicking a checkbox, that's often really, really good. So if you can disable those when applicable, you'll get a performance benefit.
And of course, we have the built-in optimization that we talked about before, which are pings are optimized at build time. In addition to that, property lists are converted to a compact binary format, which gives you two wins. The first is a nice size win. The files will be a little bit smaller. And the second one, which is really critical at app launch, is actually a CPU win, which is parsing the binary files is much, much faster than parsing the large XML files. So that's two wins for property lists that you get for free with the app. text code.
And now, we need to talk a little bit about dynamic memory. So, dynamic memory, of course, as your application is running, you want to have as small a footprint as possible. And in Leopard, we introduced these nice Objective-C2 properties, which allow you to basically have accessors and getters without actually writing them, which is really nice, or just have a nice little syntax.
One thing that we recommend, especially as the applications grow and grow, is to mark the properties as non-atomic. We've done this all over our system, and this gives you a couple of benefits. The first is that access is up to 10 times faster because we don't need to worry about thread safety, and the objects are not auto-released, so it actually saves you some memory as you're going on. And that's more important as your applications grow in size, as inevitably they will.
The next thing that you can do is cache wisely. Now, we have a very, very limited amount of memory on iPhone, but that memory is available. And so if regenerating something takes a long time, then we might make the trade-off to actually cache that object so that we don't have to compute it and so that when the user goes to that view or performs some operation, it will be really, really fast.
So don't be afraid to cache the right objects. But when you decide when you've measured that CPU win and decided you will make that decision to cache the objects and keep it in memory, design your application so that you can release those objects when they're needed. And we'll tell you how to do that in a little bit. And the other thing is to free objects when you're actually done with them. So we don't want memory hanging around as we're going.
And a nice example of that is auto-release. So auto-release is this wonderful mechanism, particularly for APIs, where you can just pass objects around. And you don't have to worry about the details of how it was allocated or I don't need to release this. It's really easy to use. But auto-release has a couple of penalties.
The first is a CPU penalty because that auto-release pool has to be freed. And the second is a memory penalty where if that object could have been released, but because it's on the auto-release pool it hasn't been yet, then you actually will be carrying along a little bit more memory until the auto-release pool is freed.
So to optimize for-- for the use of auto-release, we do two things. The first one is you're really, really familiar, if you developed on Mac OS X, with these convenience methods, such as NSString, string with format. So you might do something like create a string, stuff it into a dictionary, and then not worry about it for later with that method.
Now, in this case, auto-release isn't actually necessary to get this job done. We can actually allocate the string and then directly release it once we've transferred ownership to, say, the NSDictionary. So this gives you the memory win such that if this dictionary goes away at some point, then all that memory will be gone. And additionally, the CPU benefit, because you don't have to spend time draining the auto-release pool, it will just go away when it goes away.
And when you are using the auto release pools, there may be times when you want to prevent object accumulation. So, for example, a tight loop or there may be a lot of our system APIs will return auto released objects to make memory management easy for you. In some cases, you may want to have your own auto release pool to prevent object buildup. And the object instrument will give you a really nice view of how your object hierarchy is building up and give you some good examples of when that might be important.
Now, of course, one of the important things on iPhone is to eliminate all memory leaks. It's really, really important on all platforms to eliminate leaks. But on iPhone, it can actually be pretty deadly to have memory leaks, particularly as they build up over time as the user is using your application.
So, it's really, really important to eliminate all memory leaks before you ship your application. And of course, we want to make this as easy for you as possible. So, let's go ahead and start. So, let's go ahead and start. So, let's go ahead and start. So, let's go ahead and start. So, let's go ahead and start. So, let's go ahead and start. So, let's go ahead and start. So, let's go ahead and start. So, let's go ahead and start. So, naturally, we have a leaks instrument. And Peter Handel will demo that to you now.
As Dave mentioned, memory is a very precious resource on our system. So memory leaks are deadly, not just to performance, but also to the stability of our application. Because you can imagine, like Dave said, if our application starts gobbling up lots of memory, leaking all over the place, it may be asked to leave the party. So let's go ahead and see how can we find these leaks and fix them.
So here we are in Xcode again. And this time, we have a slightly different application. What this one does is it shows time zone information. And now what I'm going to go ahead and do is-- Click up here on-- make sure the simulator is selected. Build and go. And here it is. We see time zones. We see what you'd see if you look out the window. And There we have it. Now let's go ahead and open this guy up in the leaks tool. So we're going to say start with performance tool and leaks.
So here we are. Instruments is opened up. Here's the leaks instrument. We'll click on that. And we see, uh-oh, we have a couple leaks down here. What are we going to do? So let's click on one of these. And down here, we have a handy little box, extend detail view. When we check that, on the right side, we see the actual backtrace of the memory allocation. This is incredibly useful. And notice that these frames are colored by a framework.
Now, let's scroll to the bottom and look at the first frame in our program, which happens to be purple here. This is the region sort zones. If we double-click on it, it will take us straight to the line where that piece of memory was allocated. In this situation, it was an NS sort descriptor that we allocated called sort descriptor.
And next, we allocate an NSArray, sort descriptors, plural. A little further down, we release the sort descriptor. But there's no release of the sort descriptors, plural. So to fix this, Add a little s there. And there we go. We're releasing the NSArray that we allocated. So I'll go ahead and save that. Quit out of this. Here. And this time, I'm going to build this. Start with Performance Tool leaks.
Our application starts again. We scroll around a little bit, cross our fingers, hit the leaks button. and... two leaks. But we've gotten rid of the main other leak, so... Dave? Sometimes in my interviews, I'll ask people, how do you find leaks? And well, now you know the answer for iPhone. You just click Run in Leaks, and you're pretty much done. It's actually surprising how many leaks happen because of something like that, where you have transferred ownership to another object and just forgot to release it.
Another common case in Cocoa is just forgetting to release your instance variable in the alloc. So it's really, really easy to find them and to find your allocation points through instruments. So always make sure to run this as you are testing your application, and it's really, really helpful. I've done this about 40 times.
[Transcript missing]
So to summarize, purge all of your off-screen views and any layers that you have built up that aren't visibly on the screen when you receive these memory warnings. Remove any cached objects that you have. And if you have any cached resource files, get rid of those too. That's three things to do for low memory warnings.
So there's a lot about memory. The first is make sure you use the right compiler settings. You get Thumb for free and some other optimizations for free. The second is minimize object lifetimes. So that goes for memory that is auto-released and cached objects. When you're done with memory, get rid of them. Eliminate all memory leaks, which is really easy to do with instruments, and respond to low memory notifications. All of these things will help you write a good iPhone application that will use a small amount of memory.
Next, we'll talk a little bit about files and data. So the first thing is large files. Because you have a limited amount of memory, you may not be able to read all of them in just main memory. So we have the same APIs that are available on Mac OS X, but are even more important on iPhone, and that's MMAP.
And of course, one of the higher level interfaces to this is NSData init with contents of mapped file if you're in Cocoa.
[Transcript missing]
That's files and data. The last one is power and battery life, where we have really, really good battery life on our iPhone. And it's important that all applications that we write also have great battery life.
Everything that you do on iPhone consumes power, whether it's the CPU, your GPU, or any other part of the hardware that you're using. It will consume power. And so we want to make sure that all of our – that our power is as optimal as possible. Now, to show you a little bit, we'll go into detail about a couple of these things. But the CPU, GPU takes power, any radio that you have, so your Wi-Fi and your data connection over the cell phone network.
The display takes memory – or, sorry, takes power, and so does GPS. Everything consumes power, and so we need to optimize the things that we can as application developers. So what are some of the high-level things that we can get rid of? Well, first off is the network is very, very expensive.
So that means we don't want to constantly be transmitting and receiving data in our application. And, in fact, transmitting data is the most expensive operation that we can do. And that's what we do on iPhone. So if we do not need to transmit data, then don't. And when we transmit data, if you have a choice in the file formats, use the compact file formats.
And chatty protocols also have a significant impact on battery life. Our power management model is based on shutting things off when we don't need them. So if you know that you don't need them as quickly as possible, do a quick burst of all of your network data, and then don't do network data. It turns out that often, you don't need them. Often times just chatting, chatting, chatting can have a significant impact on battery life.
So transmission is very, very expensive. Now, Core Location gives you a great set of features that will enable you to write really good location-based applications. And there are a couple of optimizations we can make in Core Location. The first one is to stop the location service once you have a location fix. So once I know that I'm in the Moscone Center, then you don't need to have any more updates to know that Starbucks is across the street.
So stop the location service, and that will save battery life. And the second thing is only request the location accuracy that you need. So if I'm trying to figure out services that are in my general vicinity, but I don't need to know which corner block I am and get that accurate GPS fix, then we can request a location accuracy that's a little bit wider and still provide the same high-quality service.
So those are a couple things you can do in Core Location to optimize your battery life. So for battery life, you have the few optimizations that we told you about. One is, of course, performance improvements. If you're not doing things on the CPU, that actually saves battery life. So anything you do in Shark to reduce the amount of CPU that you're using will improve battery life for the users.
And that's great. They want their phone to last the whole day and a lot longer than that, hopefully. Minimize the amount of network traffic that you have and transmit data in bursts and receive data in bursts. Configure Core Location. Optimally for your app so that it only does exactly what you need it to do. And your users will have good battery life.
So we've talked about several things today. We showed you an application whose scrolling performance was terrible. And with all the advice that we gave you with the drawing optimizations, the opaque subviews, the table cell reuse, we made that application great. We talked a little bit about what we have to do as developers to make applications launch quickly so that users will want to use them over and over and over again.
We optimized memory and showed you when you do use a large amount of memory, as some applications inevitably will, how to remove caches, delete any memory that we don't need. We talked a little bit about files and data and the importance of using M mapping so that you don't have large data sets in your file. And of course, power and battery life.
Users want their phone to last. It's their connection to the outside world. It's very important to users that their phone be able to last the day and that they'll be able to call their wife or their husband when they get home and talk about their day and do whatever they want to do.
So there are a few sessions. Most of them have happened already. The 3G graphics for iPhone using OpenGL ES has some great slides and a lot of detail about performance characteristics of OpenGL ES. There's one session at 5 o'clock today, Performance Tuning Your Application with Shark, which they'll have demos on both the Mac and the iPhone, and they'll go into a lot of detail about Shark.
Getting Starting with Instruments, which is early today, 2D graphics and animation for iPhone, and debugging and profiling your iPhone application. So check out all of those videos after the session if you're interested in more details. And there are two labs that we'd love to see you at. The first one is right after this session, the iPhone Application Optimization Lab. I'll be there. Lots of other people will be there.
And tomorrow, we'll also have an iPhone Performance Optimization Lab, where we'll have, if you have games that you want to optimize, we'll have a lot of graphics people there and a lot more people there tomorrow as well. So there are a lot of opportunities for you to get one-on-one help on your application. And of course, our standard documentation, and you can contact Vicky Murley for more information. So now we can handle some questions.