iOS 内存管理

2021-04-15  本文已影响0人  你duck不必呀

基本内存管理规则

内存管理模型基于对象所有权。任何对象都可以有一个或多个所有者。只要一个对象至少有一个所有者,它就继续存在。如果一个对象没有所有者,运行时系统会自动销毁它。为了确保在拥有对象和不拥有对象时都很清楚,Cocoa设置了以下策略:

引用计数

引用计数简单来说就是,当我们创建一个新对象的时候,它的引用计数为 1,当有一个新的指针指向这个对象时,引用计数 + 1,当某个指针不再指向这个对象是,引用计数 - 1,当对象的引用计数变为 0 时,我们就将对象销毁,回收内存。

所有权策略是使用引用计数实现的

应该没有理由显式地询问对象其保留计数是多少(请参见retainCount)。结果往往是误导性的,因为您可能不知道什么框架对象保留了您感兴趣的对象。在调试内存管理问题时,您应该只关心确保代码遵守所有权规则。

结合官方文档来理解引用计数,以下代码均在MRC环境下测试
(1) 通过alloc/init ,new, copy/mutableCopy直接创建对象,是对象的所有者 retain count 等于 1

 NSObject *obj = [NSObject new];// retainCount == 1;
//...
 NSObject *obj1 = [[NSObject alloc] init];//retainCount == 1;
//...
 NSMutableString *mutStr = [[NSMutableString alloc] init];//retainCount == 1;

(2)调用 retain 返回当前对象,会使当前对象引用计数+1;

NSObject *obj = [NSObject new];//retainCount == 1;
NSObject *newObj = [obj retain];//retainCount == 2;

(3)release 使当前对象引用计数 -1;

[newObj release];retainCount == 1;

(4) 当引用计数为0时,对象被销毁,系统回收内存

[obj release];retainCount == 1;//retainCount == 0;对象销毁

关于copy和mutableCopy,深拷贝和浅拷贝的参考

关于内存管理的官方文档

memory_management_2x.png

自动引用计数ARC

ARC全称Automatic Reference Counting是苹果引入的新的内存管理技术,顾名思义即是帮助我们管理对象的引用计数,在此之前的被叫做MRC(手动管理引用计数) ,需要程序员在合适的位置插入retain/release 来管理对象的引用计数;

ARC的工作原理就是编译器在合适时机插入retain,release, autorelease来帮助我们管理计数,原理上和MRC一致,这帮助我们解决了大部分的内存问题(Foundation框架下),还有一部分涉及到core Foundation需要我们手动管理

在ARC环境下,对象的retainCount是没有参考价值的:

ARC环境下要注意一些规则:

强引用和弱引用

有两种类型的对象引用:

强引用,使对象在内存中保持“活动”状态。
弱引用,对引用对象的生存期没有影响。

代码中的大多数引用都是强引用,这是使用以下形式声明对象引用时的默认行为:

NSString * someReferenceToAString;

要创建弱引用,请使用__weak限定符,如下所示:

NSString * __weak someWeakReferenceToAString;

循环引用问题

通过引用计数的原理,我们知道当一个对象的引用计数为0的时候系统才会销毁它。假如A对B持有强引用,B也同样对A持有强引用,那么A的销毁需要B先销毁,B的销毁又依赖A,如此一来就形成相互引用


image.png

解决办法,就是我们在合适的时机主动断开对对另一个的引用:


image.png

又或者,多个对象相互持有,形成一个环状,实际可能会更复杂,环越大越难被发现


image.png

__unsafe_unretained

MRC 下通过声明其中一个变量类型为__unsafe_unretained来避免循环引用

weak

ARC下通过声明其中一个变量类型为weak来避免循环引用,它的变体有__weak,功能一样,区别是用在不同位置
具体区别查看属性关键字详解

__unsafe_unretained和weak区别

__unsafe_unretained通常用在MRC环境下, __unsafe_unretained修饰的对象被释放后,指针不会置空,而是变成一个野指针,那么此时如果访问这个对象的话,程序就会Crash

__weak修饰的对象被释放后,指向对象的指针会置空,不会产生野指针

Core Foundation 对象的内存管理

对于底层 Core Foundation 对象,框架提供了相应的 CFRetain 和 CFRelease 方法。类似于Foundation下的retain,release,按照手动管理引用计数的方式管理即可:

Foundation对象是Objective-C对象,使用Objective-C语言实现;而Core Foundation对象是C对象,使用C语言实现。两者之间可以通过__bridge、__bridge_transfer、__bridge_retained等关键字转换(桥接)。

__bridge 不改变当前对象的引用计数

__bridge_transfer 会会使当前对象的引用计数-1;

__bridge_retained 会会使当前对象的引用计数+1;

上一篇 下一篇

猜你喜欢

热点阅读