从C到C++再到Obj-C内存管理学习笔记(三)

前两篇介绍了C与C++的内存管理,这一篇介绍一下Object-C的内存管理。


Object-C是C的超集,所有C语言的特性在Object-C都可以实现。

然而在内存管理上还是存在一些不同的地方。

Object-C即面向对象C语言,其大部分的类型基于Cocoa框架,常见的有NS开头类型。

所以Object-C中大部分类型也都是以类为基础的。

Object-C中类存放于堆而非栈,故一般类对象定义都以指针形式,如:

NSString * str = @"test";

而非C++形式的自动变量类型:

NSString test; //error

Object-C中也存在非类类型non-Object类型,诸如CGRect,CGPoint等以C语言的结构体实现的类型,

按照C的管理规则,这些类型在局部代码块中也属于自动变量的范畴。

Object-C是C的超集,可能由于我看的资料比较少,在目前看过的Object-C资料看来,比较少提到类似C所提到的内存管理关键字,

内存区分类等。不过既然是C的超集,那么不管是关键字还是内存区分类,应该都是大同小异,这一点有哪位大神熟知的麻烦在下面评论区告知我一下。

下面引用前一篇的内存区分类图片来说明Object-C的内存分区:

从C到C++再到Obj-C内存管理学习笔记(三)_第1张图片

由于在前一篇中介绍过各区的作用,这里不再赘述。

Object-C中的const存在常量区,extern,static还是存储于静态存储区,C中的五大存储类中的静态变量依然可以在Object-C中延续使用,如:

static CGFloat coordinatorX = 0.6;
extern NSInteger sum = 2;

//函数中
static Bool flag = 1;
static const float = 2.0;

non-Object 的自动变量还是存储于栈,如:

viewDidLoad {

NSInteger num = 1;
CGFloat x = 2;
CGFloat y = 3;

}

而类变量存储于堆中。


Object-C在早期曾使用类似GarbegeCollection的垃圾回收机制来管理内存,不过后来逐渐被MRC取代,现在又被ARC取代。

上面提到Object-C中的对象都是放堆里,也是动态生成,这一点是Object-C与C在内存管理上最大的区别和Object-C 的特点。

而GarbegeCollection,MRC,ARC,便是用来对对象的管理,生成和释放,就如C语言中的malloc()-free()以另一种形式管理。


MRC与ARC

Object-C的内存管理中引入了引用计数retainCount的概念,顾名思义就是有多少个指针指向当前对象,当引用计数为0时,对象被释放。

MRC与ARC都基于Runtime动态实现,引用计数+1、-1,对象释放消息的发送都由Runtime来实现。


MRC(Manual Reference Counting)

MRC翻译成中文就是手动引用计数,在MRC中和C语言一样也有一些关键字,一般用于属性声明。

主要有几个,retain,assign,copy,release。

注意,下面举例代码都是在MRC环境下的!!!

Retain

当用retain 声明属性时,如:

 

@property (retain) NSString *name;

那么当我们把一个字符串对象赋给name时,字符串的引用计数retainCount 会 +1。


也可以在生成对象时直接用,如:

NSString *temp = [[NSString stringWithString:@"hello world"] retain];

这样子对象引用计数也 +1。

在accessMethor中的实现是这样的:

- (void)name:(NSString *)name {
if(self.name != name) {
[self.name release];
self.name = [name retain];
}
}



Assign

assign与retain相反,用于属性声明时,只是简单的赋值,引用计数不变,如:

@property (assign) NSInteger *age;
且一般也只用于简单数据类型,如NSInteger,NSUInteger等。

在accessMethor中的实现是这样的:

- (void)age:(NSInteger *)age {
self.age = age;
}
需要注意的是,assign所指向对象被释放时assign的对象并不知道,这是如果使用的话会crash,称野指针。


copy

copy顾名思义就是赋值,在进行对象赋值时,复制新的对象进行赋值,原对象不变,如:

@Property (copy) NSString *str;

NSString *temp = @"hello world";

self.str = temp;

这时候temp的对象引用计数不变,,新的对象被赋给str,引用计数+1;

在accessMethor中的实现是这样的:

- (void)str:(NSString *)str {
if(self.str != str) {
[self.str release];
self.str = [str copy];
}
}

也可和retain一样在生成对象时使用:

NSString *temp = [[NSString stringWithString:@"hello world"] copy];
这样原来的对象将被自动释放,新对象赋值给temp。


release

release是引用计数减一,将一个对象从一个指针处释放使用release,如上述中的:

[self.str release];
当retainCount为0时对象自动销毁。


MRC是引用计数的手动管理方式,对于程序猿来说比较麻烦,稍不注意会出现野指针和内存泄露等问题。

MRC相比起C的内存管理方式的好处是使用引用计数简化了释放过程,更加安全。

比如在C语言中如果多处引用同一个对象,一旦在某一处释放了之后,其他都变成野指针,这样是比较危险的。

而MRC的好处在于,假如使用妥当,那么对象只有在各处释放之后,引用计数减少到0时才释放,这样子便不容易出现野指针。

然而MRC在操作上还是比较困难,需要程序猿在每时每刻清除知道哪些对象该释放哪些不该释放。苹果在iOS5之后推出了ARC自动应用计数,大大方便了程序猿的工作。


ARC(Auto Reference Counting)

ARC的引入进一步方便了OC中对象的内存管理。其引入了三个新的关键字,strong,weak,unsafe_unretained。

使用这三个新的关键字,我们不需要再去手动管理引用计数,只需在声明变量的时候附上关键字就可以了。

下面介绍这三个关键字:


strong

strong和MRC中的retain作用类似,称强引用。

应用于属性声明:

@property (strong) NSString *name;
在赋值时对象引用计数自动+1,当name指向其他对象时,原来的对象引用计数自动减一,不用手动release。

在临时变量也可以使用,如:

__strong NSString *str;

NSString *str1 = @"hello world";

str = str1;
这时字符串对象引用计数+1。

值得注意的是临时变量默认为strong类型。


weak

weak和MRC中的assign作用相似,称弱引用。

应用于属性声明:

@property (weak) NSString *name;
在赋值时对象引用计数不变,当name指向其他对象时,原来的对象自动释放,不用手动release。

在临时变量也可以使用,如:

__weak NSString *str;

NSString *str1 = @"hello world";

str = str1;
这时字符串对象引用计数不变。

当str1设为nil时,str不会变成野指针,这一点和assign不同,str自动设置为nil,因此比较安全。

weak多用于消除ARC中的循环引用,比如block中的循环引用,或用于delegate。



unsafe_unretained

unsafe_unretained与weak十分相似,都只是赋值,引用计数不变,不过unsafe_unretained顾名思义是不安全,如:

@property (unsafe_unretained) NSString *name;

也可以在局部变量中加以声明,如:

__unsafe_unretained NSString *str;

NSString *str1 = @"hello world";

str = str1;
当str1释放时,str就变成野指针了,这是不安全的。

值得注意的是类属性默认为unsafe_unretained类型。


相比MRC,ARC更加方便,但也存在循环引用导致内存泄露的问题,在使用时需多加留意。


小结:

Object-C是C的超集,内存管理上也存在栈,堆,静态存储区,常量区等,只不过Object-C有object变量和non-object变量之分。non-Object变量和C中的自动变量大致上相同,在局部代码块上属于自动变量,存放于栈中。而object变量便和C有一些不同,都是动态生成的,类似C中的malloc()-free(),存放于堆中。Object-C由此引入gabegeCollection,MRC,ARC等动态基于runtime的管理机制,以引用计数为基础,以retain,weak,copy,unsafe_unretained,strong,assign等关键字来管理引用计数。ARC相对MRC使用方便,不用程序猿手动释放,但也存在循环引用等缺点。

下一篇介绍Eventloop和autoreleasepool以及C,C++,Object-C的对比总结。 

你可能感兴趣的:(C++编程)