iOS基础概念6 CPU和GPU CPU 在iOS程序中,负责对象的创建和销毁、对象属性的调整、布局的计算、文本的 计算和排版规格、图片的格式转码和解码、图像的绘制(Core Graphic) GPU 图形处理器,负责纹理的渲染,计算等等 流程: 【代码创建】 对象的创建和销毁、对象属性的调整、布局的计算、文本的计算和排版规格、图 片的格式转码和解码、图像的绘制(Core Graphic) 【CPU 】: 执行,并计算相关数据 完成后交由GPU 【GPU执行】: 将CPU提交来的数据进行渲染计算, 然后生成可以在屏幕上显示的色值数据, GPU:将数据提交给 帧缓存 【帧缓冲区】 iOS 双缓存: 前帧缓存,后帧缓存 交由 【视频控制器】 处理,去缓存读取帧 【屏幕成像:】 将帧显示到屏幕上,如果缓存没有就等下一帧 屏幕成像原理 垂直同步信号(VSync) 1. 屏幕每隔固定时间屏幕发出VSync。 2. 之后每次从帧缓存读取一帧完整数据显示 水平同步信号(HSync) 将一屏分成很多行,每次取一行的数据, 显示完一行发出 HSync 信号,再取一行直到 一屏显示完成 帧率 60FPS(Frame per Second 帧/秒) 一秒钟刷新60次 VSync 下 16.6毫秒发出一次 影响因素 CPU CALayer 与 UIView : 无触摸事件时可考虑使用CALayer 布局: Frame 与 autolayout UIImageView 显示size 大小不同被裁剪 线程的最大并发数 耗时操作放到子线程处理(比如文本的尺寸计算、绘制,图片的解码、绘制) 影响因素 GPU 短时间内大量的图片显示,可使用合成框架(涉及区域点击事件) 最大纹理尺寸是4096*4096,不要过大 减少视图的数量和层级,透明的视图 离屏渲染 光栅化操作 layer.shouldRasterize = YES 遮罩设置 layer.mask 圆角设置 layer.masksToBounds = YES&layer.cornerRadius>0 CoreGraphics 切图 阴影设置 layer.shadowXXX 设置layer.shadowPath 耗电 CPU处理 Processing 网络 Networking 定位 Location 图像 Graphics 耗电优化 降低CPU、GPU功耗 少用定时器 优化I/O操作 大量数据批量一次性写入 考虑用dispatch_io,它提供了基于GCD的异步操作文件I/O的API。使用它时, 系统会优化磁盘的访问 使用数据库 网络优化 减少、压缩网络数据 如果多次请求的结果是相同的,尽量使用缓存 使用断点续传,否则网络不稳定时可能会导致多次传输相同内容 网络不可用时,不要尝试执行网络请求 让用户取消长时间运行或者速度很慢的网络操作,设置合适的超时时间 批量传输,比如,下载视频流是,不要传输很小的数据包,直接下载整个文件或 者一大块一大块下载。如果下载广告,一次性多下载一些,然后慢慢的拿出来展 示。如果狭隘电子邮件,就一次下载多封,不要一封一封下载 定位优化 如果只是需要确定用户的位置,最好用CLLocationManager的requestLocation 方法。定位完成后,会自动让定位硬件断电。 如果不是导航引用,尽量不要实时更新位置,定位完毕就关闭掉定位服务 需要后台定位时,尽量设置pauseLocationUpdateAutomatically为YES,这 样,如果用户不太可能移动的时候,系统就会自动暂停位置更新。 尽量不要使用startMonitoringSignificantLocationChanges,优先考虑 startMonitoringForRegion: 硬件检测优化 用户移动、摇晃、倾斜设备时,会产生动作事件(motion),这些事件是由加速 度计、陀螺仪、磁力传感器等硬件检测的。在不需要检测的场合,应该及时关闭 这些硬件。 虚拟内存 & 物理内存 数据访问 不再直接通过物理地址访问 1 进程 --> 2 CPU 访问虚拟内存 ,虚拟内存偏移映射真实内存,--> 3 访问 真实内存地址 虚拟内存 虚拟内存 提高了【CPU的利用率】 本质就是: 一张虚拟地址和物理地址对应关系的映射表 每个进程都有一个独立的`虚拟内存` 大小是4G固定的 每个虚拟内存又会划分为一个一个的`页`(页的大小在`iOS中是16K,其他的是 4K`) 每次加载都是以页为单位加载的 进程间是无法互相访问的, 保证了进程间数据的安全性 缺页异常 如果在访问时,虚拟地址的内容未加载到物理内存,会发生`缺页异常 (pagefault)`,将当前进程阻塞掉,此时需要先将数据载入到物理内存,然后 再寻址,进行读取。这样就避免了内存浪费 ASLR技术 ASLR:地址空间配置随机加载 问题: 虚拟内存的起始地址 0 与大小 4G 都是固定的,非常容易被破解 利用随机方式配置数据地址空间,使某些敏感数据(例如APP登录注册、支付相 关代码)配置到一个恶意程序无法事先获知的地址,令攻击者难以进行攻击 寻址: 因物理地址是随机配置的,实际需要: 正确的内存地址 = ASLR地址 + 偏移值 通用二进制文件 不同CPU平台支持的指令不同,比如`arm64`和x86 `将多种架构的Mach-O文件打包在一起` 供系统自己选择 也被称为`胖二进制格式` 1》文件大小比较大: 比单一架构的二进制文件大很多,会占用大量的磁盘空间, 2》内存占用不影响: 但由于系统会自动选择最合适的,不相关的架构代码不会占用内存空间,且`执 行效率高`了 指令 查看 查看当前Mach-O的架构: lipo -info MachO文件 合并 lipo -create MachO1 MachO2 -output 输出文件路径 拆分 lipo MachO文件 –thin 架构 –output 输出文件路径 Mach-O 可执行文件格式,苹果系统可识别 mach object 查看Mach-O - 【方式一】otool终端命令:`otool -l Mach-O文件名` -【方式二】 `MachOView`工具(推荐):将Mach-O可执行文件拖动到 `MachOView`工具打开 Mach-O 的 几种文件类型 - `Executable`:可执行文件 - `Dylib`:动态链接库 - `Bundle`:无法被链接的动态库,只能在运行时使用dlopen加载 - `Image`:指的是Executable、Dylib和Bundle的一种 - `Framework`:包含Dylib、资源文件和头文件的集合 Mach-O 包含三个模块: 1 : header 2 :Load Commands 3 :Data 结构 - `Header Mach-O头部`:主要是Mach-O的cpu架构,文件类型以及加载命令 等信息 - `Load Commands 加载命令`:描述了文件中数据的具体组织结构,不同的数 据类型使用不同的加载命令表示 - `Data 数据`:数据中的每个段(segment)的数据都保存在这里,段的概念 与ELF文件中段的概念类似。每个段都有一个或多个部分,它们放置了具体的数 据与代码,主要包含代码,数据,例如符号表,动态符号表等等 Header 包含了 整个Mach-O文件的【关键信息】 基础架构、系统类型、指令条数等 - magic:0xfeedface(32位) 0xfeedfacf(64位),系统内核用来判断是否是 mach-o格式 - cputype:CPU类型,比如ARM - cpusubtype:CPU的具体类型,例如arm64、armv7 - filetype:由于可执行文件、目标文件、静态库和动态库等都是mach-o格 式,所以需要filetype来说明mach-o文件是属于哪种文件 - ncmds:sizeofcmds:LoadCommands加载命令的条数(加载命令紧跟 header之后) - sizeofcmds:LoadCommands加载命令的大小 - flags:标志位标识二进制文件支持的功能,主要是和系统加载、链接有关 - reserved:保留字段 文件类型 #define MH_OBJECT 0x1 /* 目标文件*/ #define MH_EXECUTE 0x2 /* 可执行文件*/ #define MH_DYLIB 0x6 /* 动态库*/ #define MH_DYLINKER 0x7 /* 动态链接器*/ #define MH_DSYM 0xa /* 存储二进制文件符号信息,用于debug分析*/ Load Commands 【作用】: Mach-O文件中 Load Commands : 主要是用于【加载指令】 【记录信息】: 动态链接器的位置、 程序的入口、 依赖库的信息、 代码的位置、 符号表的位置 mach-o 唯一标识 函数起始地址 代码签名信息 等等 【segment_command 段加载命令】: - cmd:表示加载命令类型, - cmdsize:表示加载命令大小(还包括了紧跟其后的nsects个section的大 小) - segname:16个字节的段名字 - vmaddr:段的虚拟内存起始地址 - vmsize:段的虚拟内存大小 - fileoff:段在文件中的偏移量 - filesize:段在文件中的大小 - maxprot:段页面所需要的最高内存保护(4 = r,2 = w,1 = x) - initprot:段页面初始的内存保护 - nsects:段中section数量 - flags:其他杂项标志位 - 从fileoff(偏移)处,取filesize字节的二进制数据,放到内存的vmaddr处的 vmsize字节。(fileoff处到filesize字节的二进制数据,就是“段”) - 每一个段的权限相同(或者说,编译时候,编译器把相同权限的数据放在一 起,成为段),其权限根据initprot初始化。initprot指定了如何通过读/写/执行 位初始化页面的保护级别 - 段的保护设置可以动态改变,但是不能超过maxprot中指定的值(在iOS中, +x和+w是互斥的) Data Data区域`存储了具体的 【只读、可读写代码】 例如方法、符号表、字符表、代码数据、连接器所需的数据(重定向、符号绑定 等)。主要是存储具体的数据 三大区: __TEXT 代码段:只读,包括函数,和只读的字符串 __DATA 数据段:读写,包括可读写的全局变量等 __LINKEDIT`: __LINKEDIT包含了方法和变量的元数据(位置,偏移量),以 及代码签名等信息 在`Data`区中,`Section`占了很大的比例。 主要集中体现在`TEXT`和`DATA`两段里 Section section - __TEXT __TEXT.__text __TEXT.__cstring _TEXT.__const 标签 2 _TEXT.__stubs 标签 3 _TEXT.__stubs_helper 标签 4 _TEXT.__objc_methname 标签 5 _TEXT.__objc_methtype 标签 6 _TEXT.__objc_classname 标签 7 主程序代码 C语言字符串 const 关键字修饰的常量 标签 2 用于 Stub 的占位代码, 很多地方称之为桩代码 标签 3 当 Stub 无法找到真正的符 号地址后的最终指向 标签 4 Objective-C 方法名称 标签 5 Objective-C 方法类型 标签 6 Objective-C 类名称 标签 7 section - __DATA __DATA.__data 初始化过的可变数据 解释 _DATA.__la_symbol_ptr lazy binding 的指针表,表中的 指针一开始都指向 __stub_helper 解释 _DATA.nl_symbol_ptr 非 lazy binding 的指针表,每个表项中的指针都指向一个在装载过程中,被动 态链机器搜索完成的符号 解释 _DATA.__const 没有初始化过的常量 解释 _DATA.__cfstring 程序中使用的 Core Foundation 字符串(CFStringRefs) 解释 _DATA.__bss BSS,存放为初始化的全局变量,即常说的静态内存分配 解释 _DATA.__common 没有初始化过的符号声明 解释 _DATA.__objc_classlist Objective-C 类列表 解释 _DATA.__objc_protolist Objective-C 原型 解释 _DATA.__objc_imginfo Objective-C 镜像信息 解释 __DATA.__objc_selfrefs Objective-C self 引用 解释 __DATA.__objc_protorefs Objective-C 原型引用 解释 _DATA.__objc_superrefs Objective-C 超类引用 解释