iOS内存管理

冯·诺依曼体系:运算器 控制器 存储器 输入与输出

内存即存储器,用来存储指令与数据

注:哈佛体系与普林斯顿体系的不同,使用两个独立的存储器模块,分别存储指令和数据,每个存储模块都不允许指令和数据并存;使用独立的两条总线,分别作为CPU与每个存储器之间的专用通信路径,而这两条总线之间毫无关联。

物理地址:存储器每一个字节单元给一个唯一的存储器地址,即为物理地址,又叫实际地址或绝对地址。

虚拟存储系统:操作系统层面做了一个物理地址与逻辑地址之间的映射。使用虚拟地址,作为读写的一部分。

1.程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。

2.程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为4KB)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。

3.不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。

解决两个问题,一是多个程序同时运行,二是占用很大内存的程序。

一个程序在运行时,实际要用到的指令和数据都是很有限的,不可能从头到尾同时用。那么对于一个程序来说,假装自己有非常大的空间,实际上只要有条理的把暂时要用到的部分放进物理内存供CPU访问就好,这样第二个问题解决了。那既然每个程序(进程)只用一小块,那整个物理内存就可以分给多个程序(进程)用了,第一个问题也迎刃而解。当然,这样做的前提是,数据和指令的动态进出,用完了的暂时不用的踢出内存,需要用的及时加载进来。

内存泄漏:动态存储分配的空间,在使用完毕后未释放,结果导致一直占用该内存单元,直到程序结束。

内存溢出:没有内存可用。

内存可细分五部分组成

代码(指令):静态,就是只读的东西。

初始化数据:有初始值的变量,常量。

未初始化数据:只声明未给值得变量。

栈:程序运行记录,每个线程,也就是每个执行序列各有一个,都是编译时候能确定好的,这里面的数据可以不使用指针也不会丢。

堆:最灵活,动态分配和释放,编译时不能确定,OC对象都存在堆里,通常都是用指针访问 指针从线程栈中来,但不独属于某个线程,谁分配谁释放说的是堆上对象的管理。

IOS内存管理

iOS的内存管理也是在以上的大框架下

最大的不同就是物理内存警告时

物理内存警告时,IOS会把能通过映射重新加载的内容直接清理出内存,对于不可再生的数据,iOS需要App进程配合处理,向各进程发送内存警告要求配合释放内存,对于不能及时释放足够内存的,直接kill掉进程,必要时甚至是前台运行的应用。

iOS内存管理机制的原理是引用计数,引用计数简单来说就是统计一块内存的所有权,当这块内存被创建出来的时候,它的引用计数从0增加到1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时候有另外一个对象或指针指向这块内存,那么为了表示这个后来的对象或指针对这块内存的所有权,引用计数加1变为2,之后若有一个对象或指针不再指向这块内存时,引用计数减1,表示这个对象或指针不再拥有这块内存的所有权,当一块内存的引用计数变为0,表示没有任何对象或指针持有这块内存,系统便会立刻释放掉这块内存。

其中在开发时引用计数又分为ARC(自动内存管理)和MRC(手动内存管理)。ARC的本质其实就是MRC,只不过是系统帮助开发者管理已创建的对象或内存空间,自动在系统认为合适的时间和地点释放掉已经失去作用的内存空间,原理是一样的。虽然ARC操作起来很方便,不但减少了代码量,而且降低了内存出错的概率,但因为ARC不一定会及时释放,所以程序有时候可能会占用内存较大。而MRC若做得好,通过手动管理,及时释放掉不需要的内存空间,便可保证程序长时间运行在良好状态上。

在MRC中会引起引用计数变化的关键字有:alloc,retain,copy,release,autorelease。(strong关键字只用于ARC,作用等同于retain)

alloc:当一个类的对象创建,需要开辟内存空间的时候,会使用alloc,alloc是一个类方法,只能用类调用,它的作用是开辟一块新的内存空间,并使这块内存的引用计数从0增加到1,注意,是新的内存空间,每次用类alloc出来的都是一块新的内存空间,与上一次alloc出来的内存空间没有必然联系,而且上一次alloc出来的内存空间仍然存在,不会被释放。

retain:retain是一个实例方法,只能由对象调用,它的作用是使这个对象的内存空间的引用计数加1,并不会新开辟一块内存空间,通常于赋值是调用,如:

对象2=[对象1 retain];表示对象2同样拥有这块内存的所有权。若只是简单地赋值,如:对象2=对象1;那么当对象1的内存空间被释放的时候,对象2便会成为野指针,再对对象2进行操作便会造成内存错误。

copy:copy同样是一个实例方法,只能由对象调用,返回一个新的对象,它的作用是复制一个对象到一块新的内存空间上,旧内存空间的引用计数不会变化,新的内存空间的引用计数从0增加到1,也就是说,虽然内容一样,但实质上是两块内存,相当于克隆,一个变成两个。其中copy又分为浅拷贝、深拷贝和真正的深拷贝,浅拷贝只是拷贝地址与retain等同;深拷贝是拷贝内容,会新开辟新内存,与retain不一样;真正的深拷贝是对于容器类来说的,如数组类、字典类和集合类(包括可变和不可变),假设有一个数组类对象,普通的深拷贝会开辟一块新内存存放这个对象,但这个数组对象里面的各个元素的地址却没有改变也就是说数组元素只是进行了retain或者浅拷贝而已,并没有创建新的内存空间,而真正的深拷贝,不但数组对象本身进行了深拷贝,连数组元素都进行了深拷贝,即为各个数组元素开辟了新的内存空间。

release:release是一个实例方法,同样只能由对象调用,它的作用是使对象的内存空间的引用计数减1,若引用计数变为0则系统会立刻释放掉这块内存。如果引用计数为0的基础上再调用release,便会造成过度释放,使内存崩溃;

autorelease:autorelease是一个实例方法,同样只能由对象调用,它的作用于release类似,但不是立刻减1,相当于一个延迟的release,通常用于方法返回值的释放,如便利构造器。autorelease会在程序走出自动释放池时执行,通常系统会自动生成自动释放池(即使是MRC下),也可以自己设定自动释放池

引用计数(reference counting)

OC中每一个对象有一个关联的整数retainCount用于记录对象的使用情况,当retainCount为0时,对象被销毁。

alloc copy new retain 等会使retainCount +1,

release会 -1

NSString 实际上是一个字符型常量,是没有引用计数的

赋值操作是不会拥有对象的,引用计数不会加一,要持有对象需retain

引用计数不为0,因为引用计数为1的对象release时,系统对该对象回收,不做减一操作。

自动释放池

不确定一个对象什么时候不再使用

autorelease 自动在未来释放

原理:把对象添加到自动释放池,当自动释放池销魂时,会对池中所有的对象发送release消息。

自动释放池的创建

注:

1.自动释放池只是给池中所有的对象发送release消息,当对象的引用计数>1时,对象无法销毁。

2.autorelease不会改变对象的引用计数

ARC

ios5 引入ARC(Auto Reference Counting)

编译时特性,不是运行时特性,更不是垃圾回收器

自动引用计数,在编译时,自动加上retain release等,实现内存管理。

ARC开启:可以在工程选项中选择Targets -> Compile Phases -> Compile Sources,在里面找到对应文件,添加flag: -fobjc-arc

关闭:-fno-objc-arc  ;打开:-fobjc-arc

ARC IOS5开始引入,现在绝大部分开发都是ARC模式,以下应用主要是针对ARC模式下的应用。

属性的内存管理

1.assign: 一般修饰基本数据类型

2.retain: release旧值,再retain新值

使用set方法,实质上会先保留新值,再释放旧值,再设置新值,避免新旧值一样时导致对象被释放。

MRC写法:

ARC写法:

3.copy: release旧值,再copy新值(copy内容)

一般修饰 NSString、NSArray、NSDictionary等需要保护其封装性的对象。尤其是在其内容可变的情况下 因此会拷贝一份内容给属性使用,避免可能造成的对源内容进行改动

block一般使用copy修饰

4.weak ARC新引入 可代替assign,比assign多了一个特性(置nil)

delegate 一般用weak修饰,避免循环引用

set方法时,只设置新值

5.strong ARC新引入 可代替retain

block的内存管理

1.循环引用

block一般用copy修饰,当block又引用了对象的其他成员变量时,就会对这个变量本身产生强引用,那么变量本身和它自己的block就形成了循环引用。

__weak typeof (self) weakSelf = self;

ARC下要生成一个对自身的弱引用,表示block别再对self对象retain了,避免循环引用

2.block内部变量

1.block不能改变局部变量,要改变时需加__block修饰

2.block可改变全局变量

3.static变量也可在block中修改

内存问题的分析解决

1.僵尸对象和野指针

僵尸对象:内存被回收的对象

野指针:指向僵尸对象的指针,向野指针发送消息对导致崩溃EXC_BAD_ACCESS

1 在product-scheme-edit scheme-diagnostics中将enable zombie objects勾选上,下次再出现这样的错误就可以准确定位了。

2 在Xcode-open developer tool-Instruments打开工具集,选择Zombies工具可以对已安装的应用进行僵尸对象检测。

2.循环引用

1)在product-Analyze中使用静态分析来检测代码中可能存在循环引用的问题。

2)在Xcode-open developer tool-Instruments打开工具集,选择Leaks工具可以对已安装的应用进行内存泄漏检测,此工具能检测静态分析不会提示,但是到运行时才会出现的内存泄漏问题。

3.循环中对象占用内存大

循环内产生大量的临时对象,直至循环结束才释放,可能导致内存泄漏。

解决方法:在循环中创建自己的autoReleasePool,及时释放占用内存大的临时变量,减少内存占用峰值。

4.内存泄漏

通过Analyze来进行静态代码检查,以发现在语法上显而易见的内存泄露问题

内存泄露是运行时的问题,这时可用Instruments中的Allocation和Leaks来不断重复操作App,发现和定位内存泄露点

5.过度释放

原则上都会直接crash(然而由于某些特殊的情况,不会马上crash)。

对于这种问题,可以直接使用Zombie,当过度释放发生时会立即停在发生问题的位置,同时结合内存分配释放历史和调用栈,可以发现问题。

至于上文提到的程序不会crash的原因,其实有很多。

1.对象内存释放时,所用内存并没有完全被擦除,仍有旧对象部分数据可用

2.原内存位置被写入同类或同样结构的数据

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容