iOS 根本知识(三)

藏宝库编辑 2024-9-15 10:24:11 26 0 来自 中国
目次

一. GCD和OperationQueue
二. CADisplayLink、NSTimer利用注意
三. 内存布局
四. Tagged Pointer
五. copy和mutableCopy
六. OC对象的内存管理
七. AutoreleasePool主动开释池
八. 图片的解压缩到渲染过程
九. 应用卡顿的缘故起因以及优化
十. APP的启动
一. GCD和NSOperationQueue

GCD 可用于多核的并行运算;
GCD 会主动利用更多的 CPU 内核(比如双核、四核);
GCD 会主动管理线程的生命周期(创建线程、调理任务、烧毁线程);
步调员只必要告诉 GCD 想要实行什么任务,不必要编写任何线程管理代码。
NSOperation、NSOperationQueue 是基于 GCD 更高一层的封装,完全面向对象。但是比 GCD 更简单易用、代码可读性也更高。

  • 可添加完成的代码块,在操纵完成后实行。
  • 添加操纵之间的依靠关系,设定操纵实行的优先级,方便的控制实行次序;设置最大并发数。
  • 可以很方便的取消一个操纵的实行。
  • 利用 KVO 观察对操纵实行状态的更改:isExecuteing、isFinished、isCancelled。
同步和异步紧张影响:能不能开启新的线程
同步:在当前线程中实行任务,不具备开启新线程的本领
异步:在新的线程中实行任务,具备开启新线程的本领
并发和串行紧张影响:任务的实行方式
并发:多个任务并发(同时)实行
串行:一个任务实行完毕后,再实行下一个任务
二. CADisplayLink、NSTimer利用注意



  • CADisplayLink、NSTimer会对target产生强引用,如果target又对它们产生强引用,那么就会引发循环引用。办理办法是利用署理对象NSProxy。
  • NSTimer依靠于RunLoop,如果RunLoop的任务过于繁重,大概会导致NSTimer禁绝时。而GCD的定时器会更加准时。
三. 内存布局



  • 栈区(heap):由体系去管理。地点从高到低分配。先辈后出。会存一些局部变量,函数跳转跳转时现场掩护(寄存器值生存于规复),这些体系都会帮我们主动实现,无需我们干预。以是大量的局部变量,深递归,函数循环调用都大概耗尽栈内存而造成步调瓦解 。
  • 堆区(stack):必要我们本身管理内存,alloc申请内存release开释内存。创建的对象也都放在这里。 地点是从低到高分配。堆是全部步调共享的内存,当N个这样的内存得不到开释,堆区会被挤爆,步调立马瘫痪。这就是内存泄漏。
  • 全局区/静态区(staic):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块地区, 未初始化的全局变量和未初始化的静态变量在相邻的另一块地区。步调竣事后有体系开释。
  • 常量区:常量字符串就是放在这里的,尚有const常量。
  • 代码区:存放App代码,App步调会拷贝到这里。
四. Tagged Pointer



  • 从64bit开始,iOS引入了Tagged Pointer技能,用于优化NSNumber、NSDate、NSString等小对象的存储
  • 在没有利用Tagged Pointer之前, NSNumber等对象必要动态分配内存、维护引用计数等,NSNumber指针存储的是堆中NSNumber对象的地点值
  • 利用Tagged Pointer之后,NSNumber指针里面存储的数据酿成了:Tag + Data,也就是将数据直接存储在了指针中
  • 当指针不够存储数据时,才会利用动态分配内存的方式来存储数据
  • objc_msgSend能辨认Tagged Pointer,比如NSNumber的intValue方法,直接从指针提取数据,节省了从前的调用开销
  • 怎样判断一个指针是否为Tagged Pointer?
    iOS平台,最高有用位是1(第64bit);Mac平台,最低有用位是1
5.png 五. copy和mutableCopy

6.png 六. OC对象的内存管理



  • 在iOS中,利用引用计数来管理OC对象的内存。
  • 一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会烧毁,开释其占用的内存空间。
  • 调用retain会让OC对象的引用计数+1,调用release会让OC对象的引用计数-1。
  • 当调用alloc、new、copy、mutableCopy方法返回了一个对象,在不必要这个对象时,要调用release大概autorelease来开释它;想拥有某个对象,就让它的引用计数+1;不想再拥有某个对象,就让它的引用计数-1。
7.png 七. AutoreleasePool主动开释池

AutoreleasePool(主动开释池) 是OC中的一种内存主动采取机制,在开释池中的调用了autorelease方法的对象都会被压在该池的顶部(以栈的情势管理对象)。当主动开释池被烧毁的时间,在该池中的对象会主动调用release方法来开释资源,烧毁对象。以此来达到主动管理内存的目标。
9.png
__AtAutoreleasePool 实际是一个布局体,在内部起首实行objc_autoreleasePoolPush(),然后在调用objc_autoreleasePoolPop(atautoreleasepoolobj)。
struct __AtAutoreleasePool {  __AtAutoreleasePool() {//构造函数,在创建布局体时调用atautoreleasepoolobj = objc_autoreleasePoolPush();}  ~__AtAutoreleasePool() {//析构函数,在布局体烧毁的时间调用objc_autoreleasePoolPop(atautoreleasepoolobj);}  void * atautoreleasepoolobj;};
AutoreleasePoolPage的布局


  • 每个AutoreleasePoolPage对象占用4096字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease对象的地点。
  • 全部的AutoreleasePoolPage对象通过双向链表的情势毗连在一起。
10.png


  • 调用push方法会将一个POOL_BOUNDARY入栈,而且返回其存放的内存地点
  • 调用pop方法时传入一个POOL_BOUNDARY的内存地点,会从末了一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY
  • id *next指向了下一个能存放autorelease对象地点的地区
Autorelease何时开释?

1、手动调用AutoreleasePool的开释方法(drain方法)
2、Autorelease对象是在当前的runloop迭代竣事时开释的,而它可以或许开释的缘故起因是体系在每个runloop迭代中都参加了主动开释池Push和Pop
Runloop和Autorelease的关系


  • App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。
  • 第一个 Observer 监督的事故是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建主动开释池。其 order 是 -2147483647,优先级最高,包管创建开释池发生在其他全部回调之前。
  • 第二个 Observer 监督了两个事故: BeforeWaiting(预备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 开释旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来开释主动开释池。这个 Observer 的 order 是 2147483647,优先级最低,包管其开释池子发生在其他全部回调之后。
八. 图片的解压缩到渲染过程




    • 假设我们利用 +imageWithContentsOfFile: 方法从磁盘中加载一张图片,这个时间的图片并没有解压缩;


    • 然后将天生的 UIImage 赋值给 UIImageView ;


    • 接着一个隐式的 CATransaction 捕获到了 UIImageView 图层树的厘革;


    • 在主线程的下一个 runloop 到来时,Core Animation 提交了这个隐式的 transaction ,这个过程大概会对图片举行 copy 操纵,而受图片是否字节对齐等因素的影响,这个 copy 操纵大概会涉及以下部门或全部步调:



  • 分配内存缓冲区用于管理文件 IO 息争压缩操纵;
  • 将文件数据从磁盘读到内存中;
  • 将压缩的图片数据解码成未压缩的位图情势,这是一个非常耗时的 CPU 操纵;
  • 末了 Core Animation 中CALayer利用未压缩的位图数据渲染 UIImageView 的图层。
  • CPU盘算好图片的Frame,对图片解压之后.就会交给GPU来做图片渲染



    • 渲染流程



  • GPU获取获取图片的坐标
  • 将坐标交给极点着色器(极点盘算)
  • 将图片光栅化(获取图片对应屏幕上的像素点)
  • 片元着色器盘算(盘算每个像素点的终极表现的颜色值)
  • 从帧缓存区中渲染到屏幕上
总结:图片渲染到屏幕的过程: 读取文件->盘算Frame->图片解码->解码后纹理图片位图数据通过数据总线交给GPU->GPU获取图片Frame->极点变动盘算->光栅化->根据纹理坐标获取每个像素点的颜色值(如果出现透明值必要将每个像素点的颜色*透明度值)->渲染到帧缓存区->渲染到屏幕
九. 应用卡顿的缘故起因以及优化

CPU: 盘算视图frame,文本盘算和排版,图片解码,必要绘制纹理图片通过数据总线交给GPU。
GPU: 纹理混淆,极点变动与盘算,像素点的添补盘算,渲染到帧缓冲区。
平常所说的“卡顿”紧张是由于在主线程实行了比力耗时的操纵,
可以添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控卡顿的目标。


  • 1. 屏幕呈像原理


  • 2. 卡顿产生的缘故起因
在 VSync 信号到来后,体系图形服务会通过 CADisplayLink 等机制关照 App,App 主线程开始在 CPU 中盘算表现内容,比如视图的创建、布局盘算、图片解码、文本绘制等。随后 CPU 会将盘算好的内容提交到 GPU 去,由 GPU 举行变动、合成、渲染。随后 GPU 会把渲染效果提交到帧缓冲区去,期待下一次 VSync 信号到来时表现到屏幕上。由于垂直同步的机制,如果在一个 VSync 时间内,CPU 大概 GPU 没有完成内容提交,则那一帧就会被丢弃,期待下一次时机再表现,而这时表现屏会保留之前的内容稳定。这就是界面卡顿的缘故起因。
从上面的图中可以看到,CPU 和 GPU 岂论哪个拦阻了表现流程,都会造成掉帧征象。以是开辟时,也必要分别对 CPU 和 GPU 压力举行评估和优化。


  • 3. 卡顿优化
CPU


  • 只管用轻量级的对象,比如用不到事故处置处罚的地方,可以思量利用CALayer取代UIView
  • 不要频仍地调用UIView的干系属性,比如frame、bounds、transform等属性,只管淘汰不须要的修改
  • 只管提前盘算好布局,在有必要时一次性调解对应的属性,不要多次修改属性
  • Autolayout会比直接设置frame斲丧更多的CPU资源
  • 图片的size最好刚好跟UIImageView的size保持同等
  • 控制一下线程的最大并发数目
  • 只管把耗时的操纵放到子线程:文本处置处罚(尺寸盘算、绘制)、图片处置处罚(解码、绘制)等
GPU


  • 只管制止短时间内大量图片的表现,尽大概将多张图片合成一张举行表现
  • GPU能处置处罚的最大纹理尺寸是4096x4096,一旦高出这个尺寸,就会占用CPU资源举行处置处罚,以是纹理只管不要高出这个尺寸
  • 只管淘汰视图数目和条理
  • 淘汰透明的视图(alpha<1),不透明的就设置opaque为YES
  • 只管制止出现 离屏渲染
十. APP的启动

APP的冷启动可以概括为3大阶段:dyld、runtime、main


  • 1. dyld
dyld(dynamic link editor),Apple的动态链接器,可以用来装载Mach-O文件(可实行文件、动态库等)。
启动APP时,dyld所做的事变有:

  • 装载APP的可实行文件,同时会递归加载全部依靠的动态库.
  • 当dyld把可实行文件、动态库都装载完毕后,会关照Runtime举行下一步的处置处罚.


  • 2. runtime
启动APP时,runtime所做的事变有:

  • 调用map_images举行可实行文件内容的解析和处置处罚
  • 在load_images中调用call_load_methods,调用全部Class和Category的+load方法
  • 举行各种objc布局的初始化(注册Objc类 、初始化类对象等等)
  • 调用C++静态初始化器和attribute((constructor))修饰的函数


  • 3. main
接下来就是UIApplicationMain函数,AppDelegate的application:didFinishLaunchingWithOptions:方法


  • 4. APP启动优化
15.png 保举学习资料:

Swift从入门到精通
每周一道算法题
恋上数据布局与算法(一)
恋上数据布局与算法(二)
如果必要跟我交流的话:
※ 简书:https://www.jianshu.com/u/e15d1f644bea
原文链接:https://www.jianshu.com/p/895b8e6fbeaa
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-22 04:21, Processed in 0.191532 second(s), 36 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表