面试宝点

性能优化

2020-08-29  本文已影响0人  鼬殿

CPU和GPU

在屏幕成像的过程中,CPU和GPU起着至关重要的作用
CPU(Central Processing Unit,中央处理器)
对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码、图像的绘制(Core Graphics)

GPU(Graphics Processing Unit,图形处理器)
纹理的渲染

在iOS中是双缓冲机制,有前帧缓存、后帧缓存

CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示

按次序输出到frame buffer,后一层覆盖前一层,就能得到最终的显示结果

屏幕成像原理


首先从过去的 CRT 显示器原理说起。CRT 的电子枪按照上面方式,从上到下一行行扫描,扫描完成后显示器就呈现一帧画面,随后电子枪回到初始位置继续下一次扫描。为了把显示器的显示过程和系统的视频控制器进行同步,显示器(或者其他硬件)会用硬件时钟产生一系列的定时信号。当电子枪换到新的一行,准备进行扫描时,显示器会发出一个水平同步信号(horizonal synchronization),简称 HSync;而当一帧画面绘制完成后,电子枪回复到原位,准备画下一帧前,显示器会发出一个垂直同步信号(vertical synchronization),简称 VSync

卡顿产生的原因

卡顿解决的主要思路
尽可能减少CPU、GPU资源消耗

按照60FPS的刷帧率,每隔16ms就会有一次VSync信号

卡顿优化 - CPU

// 文字计算
[@"text" boundingRectWithSize:CGSizeMake(100, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil];
  // 文字绘制
[@"text" drawWithRect:CGRectMake(0, 0, 100, 100) options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil];

卡顿优化 - GPU

离屏渲染

在OpenGL中,GPU有2种渲染方式

离屏渲染的原因

视图的图层Layer比较复杂多不能一次性绘制放入帧缓存区的时候就需要开辟离屏渲染缓冲区存储渲染数据,等到一个视图所有图层绘制混合完成后再从离屏渲染缓冲区放入帧缓存区,然后交由屏幕显示

GPU进行解码渲染 -> 离屏渲染缓存(offscreen-buffer)多图层渲染裁剪修改合并等操作 -> 帧缓存(frameBuffer)-> 视频控制器 -> 读取帧缓存区信息(位图bitmap)数模转化(数字信号处->模 拟型号) ->(逐⾏扫描)显示

CALayer图层
离屏渲染消耗性能的原因

哪些操作会触发离屏渲染?

当我们开启光栅化时,会将layer渲染成位图保存在缓存中,这样在下次使用时,就可以直接复用,提高效率

masksToBounds裁剪属性会应用到所有的图层上
只有背景色、边框以及圆角的时候,设置layer.masksToBounds都不会触发离屏渲染
一旦我们 为contents设置了内容 ,无论是图片、绘制内容、有图像信息的子视图等,再加上圆角+裁剪,就会触发离屏渲染

卡顿检测

平时所说的“卡顿”主要是因为在主线程执行了比较耗时的操作
可以添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控卡顿的目的

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),                 即将进入loop
    kCFRunLoopBeforeTimers = (1UL << 1),          即将处理Timer
    kCFRunLoopBeforeSources = (1UL << 2),         即将处理Source
    kCFRunLoopBeforeWaiting = (1UL << 5),         即将进入休眠,等待 mach_port 消息
    kCFRunLoopAfterWaiting = (1UL << 6),          接收 mach_port 消息,刚从休眠中唤醒
    kCFRunLoopExit = (1UL << 7),                  即将退出loop
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

监测主线程RunLoop的状态,如果状态在一定时长内都是 kCFRunLoopBeforeSources 或者 kCFRunLoopAfterWaiting ,则认为卡顿。

监测卡顿demo

耗电的主要来源

耗电优化

尽可能降低CPU、GPU功耗
少用定时器

优化I/O操作

网络优化

定位优化

硬件检测优化
用户移动、摇晃、倾斜设备时,会产生动作(motion)事件,这些事件由加速度计、陀螺仪、磁力计等硬件检测。在不需要检测的场合,应该及时关闭这些硬件

APP的启动

APP的启动可以分为2种

APP启动时间的优化,主要是针对冷启动进行优化

通过添加环境变量可以打印出APP的启动时间分析(Edit scheme -> Run -> Arguments)

APP的冷启动可以概括为3大阶段

dyld

runtime

启动APP时,runtime所做的事情有

到此为止,可执行文件和动态库中所有的符号(Class,Protocol,Selector,IMP,…)都已经按格式成功加载到内存中,被runtime 所管理

main

APP的启动优化

按照不同的阶段
dyld

runtime
用+initialize方法和dispatch_once取代所有的attribute((constructor))、C++静态构造器、- ObjC的+load

main

安装包瘦身

安装包(IPA)主要由可执行文件、资源组成

资源(图片、音频、视频等)

采取无损压缩
去除没有用到的资源: https://github.com/tinymind/LSUnusedResources

可执行文件瘦身

Strip Linked Product、Make Strings Read-Only、Symbols Hidden by Default设置为YES
去掉异常支持,Enable C++ Exceptions、Enable Objective-C Exceptions设置为NO, Other C Flags添加-fno-exceptions

LinkMap

生成LinkMap文件,可以查看可执行文件的具体组成


可借助第三方工具解析LinkMap文件: https://github.com/huanxsd/LinkMap
上一篇下一篇

猜你喜欢

热点阅读