IOS如何使用Instruments

How
to Use Instruments in Xcode

 Matt
Galloway
 on December 5, 2012

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+.



Learn how to troubleshoot and optimize your code with Xcode Instruments!

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 the
tutorial on this site
.

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!

Download
the starter project
 then unzip it and open it up in Xcode.

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:


  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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 TreeHide
System Libraries
 andShow 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:

- (void)setPhoto:(FlickrPhoto *)photo {
    _photo = photo;
 
    self.textLabel.text = photo.title;f
 
//    NSData *imageData = [NSData dataWithContentsOfURL:_photo.thumbnailUrl];
//    self.imageView.image = [UIImage imageWithData:imageData];
 
    [[ImageCache sharedInstance] downloadImageAtURL:_photo.thumbnailUrl
                                  completionHandler:^(UIImage *image) {
                                      self.imageView.image = image;
                                      [self setNeedsLayout];
                                  }];
}

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 clickProfile.

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:

- (void)downloadImageAtURL:(NSURL*)url completionHandler:(ImageCacheDownloadCompletionHandler)completion {
    UIImage *cachedImage = [self imageForKey:[url absoluteString]];
    if (cachedImage) {
        completion(cachedImage);
    } else {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *image = [UIImage imageWithData:data];
            [self setImage:image forKey:[url absoluteString]];
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(image);
            });
        });
    }
}

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:

- (void)setImage:(UIImage*)image forKey:(NSString*)key {
    [_cache setObject:image forKey:key];
}

This adds an image to a dictionary which is keyed on the URL the image came from. But if you look through the code, you’ll notice that the image is never cleared from that dictionary!

That’s where your unbounded memory growth is coming from! Everything is working as it should, but the app never removes things from the cache — it only ever adds them!

To fix the problem, all you need to do is have ImageCache listen to the memory warning notification that UIApplication fires. When ImageCache receives this, it must be a good citizen and clear its cache.

To make ImageCache listen to the notification, modify the init method to look like this:

- (id)init {
    if ((self = [super init])) {
        _cache = [NSMutableDictionary new];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(memoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
    }
    return self;
}

This registers the UIApplicationDidReceiveMemoryWarningNotification to execute the memoryWarning:method.
Now implement that method as below:

- (void)memoryWarning:(NSNotification*)note {
    [_cache removeAllObjects];
}

All that memoryWarning does above is remove all objects in the cache. This will ensure that nothing is holding onto the images any more and they will be deallocated.

To test this fix, fire up Instruments again (from Xcode with ⌘I) and repeat the steps you followed previously. Don’t forget to simulate a memory warning at the end!

Note: Make sure you launch from Xcode, triggering a build, rather than just hitting the red button in Instruments,
in order to make sure you’re using the lastest code.

This time the heap shot analysis should look like this:



This time, the memory usage dropped dramatically after the memory warning. There’s still some memory growth overall, but nowhere near as much as before.

The reason there’s still some growth is really due to the system libraries, and there’s not much you can do about those. It appears that the system libraries are not freeing all of their memory, which may be by design or may be a bug. All you can do in your
app is free up as much memory as possible, and you’ve already done that! :]

Well done! One more issue patched up! It must be time to ship by now! Oh, wait – there’s still the issue of the first type of leak that you haven’t yet addressed.

Call the Plumber — You’ve Got a Leak!

The next instrument you’ll be looking at is the Leaks instrument. This is used to find the first kind of leak mentioned earlier – the kind that occurs when an object is no longer referenced by anything, and eats up memory.

Detecting leaks is understandably a very complex affair, but the leaks tool remembers all objects that have been allocated and periodically scans through each object to determine if any cannot be accessed from any other object.

Close Instruments, go back to Xcode and select ProductProfile. Select the Leaks template
and click Profile:

Instruments will fire up with 2 tracks – Allocations and Leaks.
The allocations track is the same one that comes in the allocations template you used in the previous section.

You’ll only be concerned with the leaks track in this section, so click on that track to highlight it. Notice that the details you see in the rest of the Instruments window now change to reflect the state of that track.

In the detail panel, you’ll see that Automatic Snapshotting is turned on. This means
that leaks are detected every so often automatically.

The interval between snapshots can be changed, but the default of 10 seconds is good enough for your purposes right now. You can force a snapshot at any time you wish by pressing the Snapshot
Now
 button.

Back to your app! Perform a search and drill into the results. Then tap on one of the result preview rows to open the full screen viewer. Press the Rotate button at the top left, then press it again.

Go back to Instruments and wait for a moment. If you’ve done the above steps correctly, you’ll notice a leak has appeared! Your Instruments window will look like this:

Go back to the simulator and press Rotate a few more times. Then go back to Instruments and wait. Another few leaks should appear, looking like this:



Where’s the leak coming from? If the extended detail panel (on the right) isn’t open, remember the view selector control can get you there:

Open up the CGContext list in the extended detail panel. Select one of the CGContext elements in the list and look at the extended detail panel, which shows the stack trace that caused the object to be created, as below:



Once again, the frames that relate to your code are shown in black. Since there is only one, double click on it to see the code for that method.

The method in question is rotateTapped:, which is the handler called when the Rotate
button is tapped. This method rotates the original image and creates a new image, as below:

- (void)rotateTapped:(id)sender {
    UIImage *currentImage = _imageView.image;
    CGImageRef currentCGImage = currentImage.CGImage;
 
    CGSize originalSize = currentImage.size;
    CGSize rotatedSize = CGSizeMake(originalSize.height, originalSize.width);
 
    CGContextRef context = CGBitmapContextCreate(NULL,
                                                 rotatedSize.width,
                                                 rotatedSize.height,
                                                 CGImageGetBitsPerComponent(currentCGImage),
                                                 CGImageGetBitsPerPixel(currentCGImage) * rotatedSize.width,
                                                 CGImageGetColorSpace(currentCGImage),
                                                 CGImageGetBitmapInfo(currentCGImage));
 
    CGContextTranslateCTM(context, rotatedSize.width, 0.0f);
    CGContextRotateCTM(context, M_PI_2);
    CGContextDrawImage(context, (CGRect){.origin=CGPointZero, .size=originalSize}, currentCGImage);
 
    CGImageRef newCGImage = CGBitmapContextCreateImage(context);
    UIImage *newImage = [UIImage imageWithCGImage:newCGImage];
 
    self.imageView.image = newImage;
}

Again, Instruments can only give you a hint here as to where the problem lies; it can’t tell you exactly where the leak is. It’s only able to show you where the leaked object was created. It’s then your job to work out what the problem is! :]

You may think that ARC should have taken care of all the memory management, and that there couldn’t possibly be a leak in the code…right?

Recall that ARC only deals with Objective-C objects. It doesn’t manage the retain and release of CoreFoundation objects which are not Objective-C objects.

Ah, now it’s starting to become obvious what the problem is — the CGContextRef and CGImageRef objects are never released! To fix that, add the following two lines of code at the end of the rotateTapped method:

CGImageRelease(newCGImage);
CGContextRelease(context);

These two calls are required to balance out the retain counts of these two objects. The moral of this story is that you still need to know about reference counting — even if you use ARC in your project!

From within Xcode, use ⌘I again to build and run the app in Instruments.

Look at the app again in Instruments using the leaks instruments and see if that leak’s been fixed. If you’ve followed the above steps correctly, the leak should be gone!

Well done! SHIP IT! :]

时间: 2024-10-29 19:50:14

IOS如何使用Instruments的相关文章

[译] 原生 iOS(Swift) 和 React-Native 的性能比较

本文讲的是[译] 原生 iOS(Swift) 和 React-Native 的性能比较, 原文地址:Comparing the Performance between Native iOS (Swift) and React-Native 原文作者:John A. Calderaio 译文出自:掘金翻译计划 译者:Deepmissea 校对者:gy134340,Danny1451 原生 iOS(Swift) 和 React-Native 的性能比较 React-Native 是一个混合的移动框架

iOS 各版本中的新特性(What's New in iOS)- 目录翻译完成

iOS 各版本中的新特性(What's New in iOS) 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 介绍 Introduction文档组织结构 Organization of Thi

《iOS App界面设计创意与实践》——iOS开发工具和资源

iOS开发工具和资源iOS App界面设计创意与实践设计和开发iOS应用程序的好处之一是,提供给你的工具和资源的质量和数量.苹果公司在开发工具方面做得很好,提供了专用于创建iOS应用程序的开发工具.此外,苹果公司为iOS软件开发工具包(SDK)和iOS应用程序编程接口(API)编写了大量的文档和参考资料.可以用来设计和开发iOS应用程序的4个主要工具如下: Xcode: Interface Builder: iOS Simulator: Instruments. DevNote_AppIcon1

我的失败与伟大 —— 招人面试的技巧

招人,是困扰绝大多数创业公司的世界级难题:就连雷军这样的大佬,不是都说:"我用80%的时间招人"么 在创业的18个月里,我在招人面试方面投入了大量精力,边思考边行动,再用行动的结果纠偏思考的模式,从一个对招人面试一窍不通的纯菜鸟成长为一个小有见解的准HR. 在本文中,我会试图总结出一套创业公司招人面试的方法,相信能够对90%以上的创业公司起到帮助. 我们的招人套路一般是这样的: 从各种渠道收集简历: 初步筛选简历: 寻找合格简历的联系方式: 约面试: 进行N轮面试: 给面试合格者发of

手机淘宝性能优化

该文章来自于阿里巴巴技术协会(ATA)精选文章. 手机淘宝性能优化 前言 为了满足不同用户的多样性购物需求,过去两年里手淘的业务不断膨胀,已经从单一的购物工具成为了购物内容平台.在手淘业务快速增长的同时,也带来一些副作用,很多操作环节和页面因为承载功能太多,展示的速度变慢,用户等待时间变长.性能优化势在必行.  我们根据手机淘宝用户的购物操作流程,对主链路进行了划分,分为启动,首页加载,搜索,购物车,下单,支付环节,订单查看等七个环节,每个步骤和模块都做到监控,以量化数据为指导来进行优化. 下面

Instruments Tutorial for iOS: How To Debug Memory Leaks【转】

If you're new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting! Call the plumber, it's-a-leaking! Update 4/12/13: These days, you should probably be using Apple's new Automatic Reference Counting (ARC) techn

iOS 7中如何使用脚本关闭VoIP APP进程

背景介绍 VoIP 类型的APP有个特性,就是需要一直在后台保持运行,以便能够随时接收来电.正因为系统提供给VoIP进程的这种特殊机制,导致我们没法直接用kill命令完全查杀VoIP进程.关于这点更加详细的信息,可参考如下Apple developer网站的介绍: "Because VoIP apps need to stay running in order to receive incoming calls, the system automatically relaunches the a

IOS 内存优化和调试技巧

基础部分 1: 图片内存大小小结 a: 图片:是占用内存的大户,尤其是手机游戏图片资源众多.对图片资源在内存中占用量的计算成为J2ME游戏开发者的经常性工作,CoCoMo来解释一下如何计算图片在内存中的占用量:内存占用量=宽*高*像素字节数,其中像素字节数因机型而异. 例如一张64*64的图片在7210上的内存占用量=64*64*1.5=6144(字节)=6K.在S60上的内存占用量=64*64*2=8192 (字节)=8K.像素字节数因机型而异,例如 7210是4096色机型,也就是说用12位

ios-Delphi XE8开发FMX 的App,IOS持续使用一段时间程序被系统杀了。。什么原因??

问题描述 Delphi XE8开发FMX 的App,IOS持续使用一段时间程序被系统杀了..什么原因?? 程序主要用于数据库查询,有40个Form,在安卓里是完全没问题的,但是到ios里就会闪退.delphi官方说一套代码,多平台通用,结果悲剧了.检查代码,感觉没有错误,在安卓下一只查询数据也不会闪退.可到了Iphon6上,刚开始没问题,多查询几次就会闪退,郁闷死我了.后来以为窗体太多是不是太占内存,就改代码,除了主窗体,其他窗体一律动态创建,关闭窗体时候马上Free:Clientdataset