1、内存的几大区域
iOS的内存分布区域大致分为:栈区(stack)、堆区(heap)和全局静态区(static)。
栈区:主要存放局部变量和函数的参数值等相关变量,由编译器自动分配并释放。栈是系统数据结构,对应线程/进程是唯一的。
优点:是快速高效,缺点时有限制,数据不灵活。[先进后出]
堆区:存放alloc,new等关键字生成的对象,由程序员分配和释放,如果程序员不释放,程序结束时,可能会由操作系统回收。(ps:虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存,释放内存匹配是良好程序的基本要素。而且,若程序员不释放,会出现内存泄露。)
优点:是灵活方便,数据适应面广泛,但是效率有一定降低。
全局静态区:主要存放静态数据,全局数据和常量。
以上是针对静态数据、全局数据和常量的一个区分。
PS:
1.申请后的系统是如何响应的?
栈:由编译器自动分配和释放,只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:操作系统中有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,并将该结点的空间分配给程序。由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
2.申请大小的限制是怎样的?
栈:栈是向低地址扩展的数据结构,是一块连续的内存的区域。是栈顶的地址和栈的最大容量是系统预先规定好的,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数 ) ,如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
打个比喻来说:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
2、多线程
多线程分为:pthread、NSTread、GCD和NSOperation四种。
多线程的原理:
同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)
多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)
如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象
问:如果线程非常非常多,会发生什么情况?
CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源,每条线程被调度执行的频次会降低,也就是说线程的执行效率降低。
多线程的优点:
能适当提高程序的执行效率,能适当提高资源利用率(CPU、内存利用率)
多线程的缺点:
开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
线程越多,CPU在调度线程上的开销就越大
程序设计更加复杂:比如线程之间的通信,多线程的数据共享
更倾向于哪一种多线程呢?
GCD技术是一个轻量的,底层实现隐藏的神奇技术,我们能够通过GCD和block轻松实现多线程编程。有时候,GCD相比其他系统提供的多线程方法更加有效,当然,有时候GCD不是最佳选择。另一个多线程编程的技术NSOprationQueue让我们能够将后台线程以队列方式依序执行,并提供更多操作入口,这和GCD的实现有些类似。
这种类似不是一个巧合,在早期,MacOX 与 iOS 的程序都普遍采用Operation Queue来进行编写后台线程代码,而之后出现的GCD技术大体是依照前者的原则来实现的,而随着GCD的普及,在iOS 4 与 MacOS X 10.6以后,Operation Queue的底层实现都是用GCD来实现的。
3、怎么防止别人反编译你的app?
1)本地数据加密
对NSUserDefults,sqlite存储文件数据加密,保护账号和关键信息。
2)URL编码加密
对程序中出现的URL进行编码加密,防止URL被静态分析
3)网络传输数据加密
对客户端传输提供加密方案,有效防止通过网络接口的拦截获取数据
4)方法体,方法名高级混淆
对应用程序的方法名和方法体进行混淆,保证源码被逆向后无法解析代码
5)程序结构混排加密
对应用程序逻辑结构进行打乱混排,保证源码可读性降到最低
6)借助第三方APP加固,例如:网易云易盾
4、优化从几方面入手
一、首页启动速度
启动过程中做的事情越少越好(尽可能将多个接口合并)
不在UI线程上作耗时的操作(数据的处理在子线程进行,处理完通知主线程刷新节目)
在合适的时机开始后台任务(例如在用户指引节目就可以开始准备加载的数据)
尽量减小包的大小
优化方法:
量化启动时间、启动速度模块化、辅助工具(友盟、听云、Flurry)
二、页面浏览速度
json的处理:(iOS自带的NSJSONSerialization,Jsonkit,SBJson)
数据的分页:(后端数据多的话,就要分页返回,例如网易新闻,或者微博记录)
数据压缩:(大数据也可以压缩返回,减少流量,加快反应速度)
内容缓存:(将页面信息缓存到本地,从本地加载,可以缓存到内存,或者数据库,根据情况而定)
延时加载tab:(比如app有5个tab,可以先加载第一个要显示的tab,其他的在显示时间加载,按需加载)
算法的优化:(核心算法的优化,例如有些app有个 联系人姓名用汉语拼音的首字母排序)
三、操作流畅度优化
tableView优化(tableView cell的加载优化)
ViewController加载优化(不同view之间的跳转,可以提前准备好数据)
四、数据库的优化
数据库设计上面的重构
查询语句的优化
分库分表(数据太多的时候,可以分不同的表或库)
五、服务器端和客户端的交互优化
客户端尽量减少请求
服务器端尽量做多的逻辑处理
服务器端和客户端采取推拉结合的方式(可以利用一些同步机制)
通信协议的优化(减少报文的大小)
电量使用优化(尽量不要使用后台运行)
5、runloop内部实现逻辑
可以看到,实际上RunLoop就是这样一个函数,气内部是一个do-while循环。当你调用CFRunLoopRun()时,线程就会一直停留在这个循环里;直到超时或被手动停止,该函数才会返回。
。。。