iOS设备中某个应用内存使用超过单个进程上的限制,会被系统终止使用。
内存问题常出现在重复的内存释放
和循环引用
的情况。
内存消耗
内存消耗
指的是应用消耗的RAM
。iOS的虚拟内存模型并不包含交换内存,意味着不会被用来分页内存。
应用中内存消耗分为两部分:栈大小
和堆大小
。
栈大小
应用中新线程都有专用的栈空间,该空间由保留的内存和初始提交的内存组成。栈可以在线程存在期间自由使用。线程的最大空间很小,这就决定了以下限制:
main() { //第一个栈帧
func1(); //第二个栈帧
}
func1() {
func2(); //在func1()上增加一个栈帧。
}
- 一个方法中最多可以使用的变量个数的限制,所有的变量都会载入方法的栈帧中,并消耗一定栈空间。
- 视图层级中可以嵌入的最大视图深度的限制,渲染符合视图,整个视图层级树种递归调用layoutSubviews和drawRect方法。若层级过深,会导致栈溢出。
堆大小
每个进程的所有线程共享同一个堆。应用并不能控制分配给它的堆。只有操作系统才能管理堆。
通过类创建的对象相关数据都存放在堆中。类可能包含属性或值类型的实例变量(iVars,基本数据类型),如int、char或struct。因为对象是在堆内创建的,所以他们只消耗内存。
使用NSString、载入图片、创建或使用JSON/XML数据、使用视图等都会消耗大量的堆内存。需要关注平均值和峰值内存使用的最小化。
当对象被创建并赋值时,数据可能会从栈复制到堆。类似的,当值仅在内部使用时,也可能会被从堆复制到栈。
虽然没有强制规定,但内存最好不要超过80%~85%,要给系统内核留下足够内存。**不要忽视didReceiveMemoryWarning
信号。
内存管理模型
管理模型基于持有关系(引用计数?retain or release?)的概念。如果一个对象正处于被持有状态,那它占用的内存就不能被回收。
当一个对象创建于某个方法内部十,那么方法就持有该对象。如果这个方法返回,则调用者声称建立了持有关系。这个值可以付给其他变量,对应的变量同样会声称建立了持有关系。
一旦与某个对象相关的任务全部完成,就是放弃了持有关系。这一过程中没有转移持有关系,而是分别增加或减少了持有者的数量。当持有者的数量降为零时,对象会被释放ÿ