黑马程序员 --- 内存管理的MRC和ARC

内存管理的MRC和ARC

内存管理

概念:  由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,个app可用的内存是被限制的,如果一个app使用的内存超过20M,则系统会向该app发送Memory Warning消息。收到此消息后,需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量,否则程序会崩溃。

OC内存管理的范围:管理任何继承NSObject的对象,对其他的非OC基本数据类型无效。

  本质原因: 因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露。

Objective-C提供了三种内存管理方式:

1.MannulReference CountingMRC,手动管理,在开发 iOS4.1之前的版本的项目时我们要自己负责使用引用计数来管理内存,比如要手动 retainreleaseautorelease 等,而在其后的版本可以使用 ARC,让系统自己管理内存。)

2.automatic reference countingARC,自动引用计数,iOS4.1 之后推出的)

3.garbage collection(垃圾回收)。iOS不支持垃圾回收;

开发中如何使用: 需要理解MRC,但实际使用时尽量用ARC


从上图我们可以看出ARC开发程序的代码会比MRC少一大部分。

内存管理中的MRC

黄金法则:The basic rule to apply is everything that increases the reference counter with

 alloc,[mutable]copy,[withZone]or retain is in charge of the corresponding [auto]release.

翻译如果对一个对象使用了alloc[mutable]copyretain,那么你必须使用相应的release或者autorelease

 

对引用计数器的操作:

1.判断对象要不要回收的唯一依据(存在一种例外:对象值为nil时,引用计数为0,但不回收空间)就是计数器是否为0,若不为0则存在。

给对象发送消息,进行相应的计数器操作。

2.创建对象时:使计数器+1

3.retain消息:使计数器+1,该方法返回对象本身

4.release消息:使计数器-1(并不代表释放对象)

5.retainCount消息:获得对象当前的引用计数器值 %ld %tu

//main.m
Person *p = [[Person allco] init];
[p retain];  //retaincount = 2
[p release]; //retaincount = 1

[p retain];  //retaincount = 2
[p retain];  //retaincount = 3
[p release]; //retaincount = 2
[p release]; //retaincount = 1

[p release]; //retaincount = 0


内存管理的关键如何判断对象被回收 ?

1)一定要[super dealloc],而且要放到最后,意义是:先释放子类占用的空间在释放父类占用的空间

2)对self(当前)所拥有的的其他对象做一次release操作

-(void)dealloc
{
<span style="white-space:pre">	</span>NSLog(@"对象被销毁了");
<span style="white-space:pre">	</span>[_car release];
<span style="white-space:pre">	</span>[super dealloc];
}

注意永远不要直接通过对象调用dealloc方法(实际上调用并不会出错)

一旦对象被回收了它占用的内存就不再可用坚持使用会导致程序崩溃(野指针错误)为了防止调用出错,可以将“野指针”指向nil0)。p = nil;如果对象内存被回收了,就会调用重写父类的dealloc方法


内存管理的原则:

1)谁创建,谁release

1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法

2)不是你创建的就不用你去负责

2)谁retain,谁release;只要你调用了retain,无论这个对象时如何生成的,你都要调用release

3有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1

-(void)setCar:(Car *)car
{
<span style="white-space:pre">	</span>if(car!=_car)  //先判断传入的是否跟_car相等
<span style="white-space:pre">	</span>{//2 对旧对象做一次release
<span style="white-space:pre">		</span>[_car release];//若没有旧对象,则没有影响
<span style="white-space:pre">		</span>_car=[car retain]; //3.对新对象做一次retain</span>
<span style="white-space:pre">	</span>}
}

野指针错误:访问了一块坏的内存(已经被回收的,不可用的内存)。

僵尸对象:所占内存已经被回收的对象,僵尸对象不能再被使用。( 默认情况下xcode为了提高编码效率,不会时时检查僵尸对象, 打开僵尸对象检测),当对象的retaincount0时,p = nil;

 

关于nilNilNULL的区别:

nil: A null pointer to an Objective-C object. (指向对象的空指针)

Nil: A null pointer to an Objective-C class.(指向类的空指针)

NULL: A null pointer to anything else. ( #define NULL ((void *)0) )

NULL是一个通用指针(泛型指针)。




内存管理的ARC

ARC 下不在使用retainreleaseautorelease ,dealloc这些关键字,取而代之是strongweak指针。ARC所做的只不过是在代码编译时为你自动在合适的位置插入releaseautorelease

ARC的判断准则:

只要没有强指针指向对象,对象就会被释放。

注意:当使用ARC的时候,暂时忘记“引用计数器”,因为判断标准变了。


图1

图1是两个指针指向同一块内存区域


图2

图2说明了当强指针不在指向那块区域后,不管是否有弱指针都会被释放的

//此时刚被初始化就会被释放掉,因为没有强指针指向当前内存
__weak Person *p = [[Person alloc] init];
//强指针指向一块区域
__strong Person *p2 = [[Person alloc] init];
p2 = nil;   //此时p2所指的内存区域被释放
//p3为强指针,默认的
Person *p3 = [[Person alloc] init];

ARC下循环引用问题:
//Person.h
#import <Foundation/Foundation.h>
@class Dog;
@interface Person : NSObject
//dog是strong 强指针
@property (nonatomic,strong) Dog *dog;
@end


 
 
//Dog.h
#import <Foundation/Foundation.h>
@class Person;
@interface Dog : NSObject
//狗的主人 也是strong 强指针
@property (nonatomic,strong) Person *owner;
@end

//main.m
Person *p = [[Person alloc] init];
Dog *d = [[Dog alloc] init];
p.dog = d;
d.owner = p; //此时p和d陷入了互相调用的循环中


图上很明显就可以看出来:当栈里面的p和d被释放后,堆里面的两块内存区域由于互相指向所以都不能被释放掉,打破这种循环引用的问题,我们只能打破其中一个引用设置为weak指针,如:
//Person.h
@property (nonatomic,weak) Dog *dog;

或者是
//Dog.h
@property (nonatomic,weak) Person *owner;
这样解决后,_owner指向Person为弱指针,一旦p生命周期结束,Person这块区域就会被释放掉;_dog指向Dog为弱指针,一旦d声明周期结束,Dog这块区域就会被释放掉。

从上面的ARC和MRC的解析,你是否对它们有一定的了解了呢?


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值