专栏名称: Cocoa开发者社区
CocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。
目录
相关文章推荐
51好读  ›  专栏  ›  Cocoa开发者社区

深入剖析 iOS 性能优化

Cocoa开发者社区  · 公众号  · ios  · 2017-07-23 11:14

正文

请到「今天看啥」查看全文


13  libsystem_pthread.dylib  0x07fff93c17637 _pthread_wqthread + 729

14  libsystem_pthread.dylib  0x07fff93c1540d start_wqthread + 13


主线程闲置时


Thread 0 Crashed:: Dispatch queue: com.apple.main-thread

0   libsystem_kernel.dylib     0x00007fff906614de mach_msg_trap + 10

1   libsystem_kernel.dylib     0x00007fff9066064f mach_msg + 55

2   com.apple.CoreFoundation   0x00007fff9a8c1eb4 __CFRunLoopServiceMachPort

3   com.apple.CoreFoundation   0x00007fff9a8c137b __CFRunLoopRun + 1371

4   com.apple.CoreFoundation   0x00007fff9a8c0bd8 CFRunLoopRunSpecific + 296

...

10  com.apple.AppKit           0x00007fff8e823c03 -[NSApplication run] + 594

11  com.apple.AppKit           0x00007fff8e7a0354 NSApplicationMain + 1832

12  com.example                0x00000001000013b4 start + 52


主队列


Thread 0 Crashed:: Dispatch queue: com.apple.main-thread

12  com.apple.Foundation      0x00007fff931157e8 __NSBLOCKOPERATION_IS_CALLING
_OUT_TO_A_BLOCK__ + 7

13  com.apple.Foundation      0x00007fff931155b5 -[NSBlockOperation main] + 9

14  com.apple.Foundation      0x00007fff93114a6c -[__NSOperationInternal _
start:] + 653

15  com.apple.Foundation      0x00007fff93114543 __NSOQSchedule_f + 184

16  libdispatch.dylib         0x00007fff935d6c13 _dispatch_client_callout + 8

17  libdispatch.dylib         0x00007fff935e2cbf _dispatch_main_queue_callback
_4CF + 861

18  com.apple.CoreFoundation  0x00007fff8d9223f9 __CFRUNLOOP_IS_SERVICING_THE
_MAIN_DISPATCH_QUEUE__

19  com.apple.CoreFoundation  0x00007fff8d8dd68f __CFRunLoopRun + 2159

20  com.apple.CoreFoundation  0x00007fff8d8dcbd8 CFRunLoopRunSpecific + 296

...

26  com.apple.AppKit          0x00007fff999a1bd3 -[NSApplication run] + 594

27  com.apple.AppKit          0x00007fff9991e324 NSApplicationMain + 1832

28  libdyld.dylib             0x00007fff9480f5c9 start + 1



I/O 性能优化


I/O 是性能消耗大户,任何的 I/O 操作都会使低功耗状态被打破,所以减少 I/O 次数是这个性能优化的关键点,为了达成这个目下面列出一些方法。

  • 将零碎的内容作为一个整体进行写入

  • 使用合适的 I/O 操作 API

  • 使用合适的线程

  • 使用 NSCache 做缓存能够减少 I/O



控制 App 的 Wake 次数


通知,VoIP,定位,蓝牙等都会使设备从 Standby 状态唤起。唤起这个过程会有比较大的消耗,应该避免频繁发生。通知方面主要要在产品层面多做考虑。定位方面,下面可以看看定位的一些 API 看看它们对性能的不同影响,便于考虑采用合适的接口。

连续的位置更新


[locationManager startUpdatingLocation]


这个方法会时设备一直处于活跃状态。

延时有效定位


[locationManager allowDeferredLocationUpdatesUntilTraveled: timeout:]

```

高效节能的定位方式,数据会缓存在位置硬件上。适合于跑步应用应该都采用这种方式。

重大位置变化

```objc

[locationManager startMonitoringSignificantLocationChanges]


会更节能,对于那些只有在位置有很大变化的才需要回调的应用可以采用这种,比如天气应用。

区域监测


[locationManager startMonitoringForRegion:(CLRegion *)]


也是一种节能的定位方式,比如在博物馆里按照不同区域监测展示不同信息之类的应用比较适合这种定位。

经常访问的地方


// Start monitoringlocationManager.startMonitoringVisits()// Stop
monitoring when no long
er neededlocationManager.stopMonitoringVisits()


总的来说,不要轻易使用 startUpdatingLocation() 除非万不得已,尽快的使用 stopUpdatingLocation() 来结束定位还用户一个节能设备。


内存对于性能的影响


首先 Reclaiming 内存是需要时间的,突然的大量内存需求是会影响响应的。


如何预防这些性能问题,需要刻意预防么


坚持下面几个原则争取在编码阶段避免一些性能问题。

  • 优化计算的复杂度从而减少 CPU 的使用

  • 在应用响应交互的时候停止没必要的任务处理

  • 设置合适的 QoS

  • 将定时器任务合并,让 CPU 更多时候处于 idle 状态

那么如果写需求时来不及注意这些问题做不到预防的话,可以通过自动化代码 检查 的方式来避免这些问题吗?


如何检查


根据这些问题在代码里查,写工具或用工具自动化查?虽然可以,但是需要考虑的情况太多,现有工具支持不好,自己写需要考虑的点太多需要花费太长的时间,那么什么方式会比较好呢?


通过监听主线程方式来监察


首先用 CFRunLoopObserverCreate 创建一个观察者里面接受 CFRunLoopActivity 的回调,然后用 CFRunLoopAddObserver 将观察者添加到 CFRunLoopGetMain() 主线程 Runloop 的 kCFRunLoopCommonModes 模式下进行观察。

接下来创建一个子线程来进行监控,使用 dispatch_semaphore_wait 定义区间时间,标准是 16 或 20 微秒一次监控的话基本可以把影响响应的都找出来。监控结果的标准是根据两个 Runloop 的状态 BeforeSources 和 AfterWaiting 在区间时间是否能检测到来判断是否卡顿。


如何打印堆栈信息,保存现场


打印堆栈整体思路是获取线程的信息得到线程的 state 从而得到线程里所有栈的指针,根据这些指针在 符号表里找到对应的描述即符号化解析,这样就能够展示出可读的堆栈信息。具体实现是怎样的呢?下面详细说说:


获取线程的信息


这里首先是要通过 task_threads 取到所有的线程,


thread_act_array_t threads; //int 组成的数组比如 thread[1] = 5635

mach_msg_type_number_t thread_count = 0; //mach_msg_type_number_t 是 int 类型

const task_t this_task = mach_task_self(); //int

//根据当前 task 获取所有线程

kern_return_t kr = task_threads(this_task, &threads, &thread_count);


遍历时通过 thread_info 获取各个线程的详细信息


SMThreadInfoStruct threadInfoSt = {0};

thread_info_data_t threadInfo;

thread_basic_info_t threadBasicInfo;







请到「今天看啥」查看全文