Objective-C 内存管理简介
status
category
date
summary
slug
icon
tags
password
不管学习什么操作系统开发,都会接触到内存管理的相关知识。在大二时通过操作系统原理这门课学习了一些基本概念,所以想针对具体的iOS开发,在这里做一些实践中的记录。
内存管理基础概念
对于常见的操作系统知识,例如堆栈、虚拟内存、页式存储等概念,我就不在赘述,主要介绍iOS中的应用场景。
引用计数
引用计数(Reference Count)是一种管理对象生命周期的方式,也可以说是众多垃圾回收算法之一。当我们新创建一个对象时,它的引用计数为1,每当有一个新的指针指向该对象,它的引用计数就增加1;当某个原本指向该对象的指针不再指向它,它的引用计数就减少1。当某个对象的引用计数为0时,说明这个对象不被任何指针指向,也就是没有其他对象引用它,我们就可以将对象摧毁,并回收内存。目前使用引用计数来管理内存的语言主要包括:Objective-C,Swift,C++11,PHP,Python等等。利用引用计数管理内存的基本过程如下图所示:

引用计数的优点在于,程序员不需要思考何时何地来释放对象。例如,对象A将对象M传递给对象B,对象A并不知道对象B需要如何使用对象M,可能是临时使用,也可能是长时间持有,A也就无法知道什么时候来释放M了。如果释放工作交给B呢?在对象传递次数增多时,一个对象的管理需要多个对象的配合,使代码更加复杂。引用计数很好地解决了这个问题,所有对象都遵守引用计数的增减规则,对象的释放就可以由引用计数管理了。
MRC
MRC(Manual Reference Counting)指的是手动引用计数,通过
alloc、new、copy、retain、release
等方法实现引用计数的改变。回到上面的例子,只能释放自己生成、自己持有的对象,当需要释放非自己生成、或非自己持有的对象时,需要使用autorelease
等方法。MRC最大的弊病在于,程序员需要对每个对象手动进行引用计数管理,在此耗费很大的时间和精力。ARC
ARC(Automatic Reference Counting)代表自动引用计数,由编译器在编译时自动插入对象内存管理的相关方法,我们可以在Xcode中指定某些文件使用或不适用ARC。ARC和MRC在内存管理的本质上并没有区别,只是管理引用计数方面有所不同。
所有权
在ARC中,id类型和对象类型必须使用所有权修饰符:
__strong
:默认所有权,表示强引用,引用变量超出作用域时就会被释放
__weak
:弱引用,不持有对象实例,如果对象被废弃,则弱引用自动失效且置为nil
__unsafe_unretained
:表示变量不属于编译器管理的内存对象,和弱引用一样不持有对象
属性的声明和所有权修饰符也有对应关系:
属性声明 | 所有权 |
assign | __unsafe_unretained |
copy | __strong |
retain | __strong |
strong | __strong |
Unsafe_unretained | __unsafe_unretained |
weak | __weak |
常见的内存泄漏场景
内存泄漏指的是某块分配给对象的内存,在对象不再被需要时,该部分内存仍然被占据没有释放,最终造成内存溢出。
非OC对象
ARC只负责OC对象的内存管理,对于诸多C语言框架例如
CoreFoundation
下的对象,需要我们手动管理。循环引用
两个对象如果使用强引用互相持有,即使两个对象不再被需要,它们的引用计数仍然不会被置为0,造成内存泄漏。一般来讲,可以通过设置弱引用解决这个问题,但循环引用也有很多种具体的情况。
- block造成的循环引用
当前类持有的block又使用了self或者自己的实例变量,就会造成循环引用,一般通过在block中使用弱化过的weakSelf解决。
- delegate造成的循环引用
通过持有weak delegate解决
Loading...