您的位置:首页 > 职场人生

黑马程序员—IOS基础之OC—内存管理

2015-07-20 21:51 441 查看
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——

一、OC内存管理基本概念

因为手机的内存有限,为了保证每个程序能正常运行,要对内存进行管理。当内存不再使用的时候,就应该回收它的空间。OC中内存管理的范围。BSS段、数据区和代码区是在程序启动的时候加载的,栈区存放的时局部变量,不需要程序员对其进行内存管理,所以OC中内存的管理范围是管理任何继承NSObject的对象,对其他的基本数据类型无效。


二、内存管理的原理和分类

1、内存管理的原理

(1)对象的所有权及引用计数
任何自己创建的对象归自己所有,即通过allow、new创建的对象。可以通过retain获得对象的所有权。
(2)引用计数器
引用计数器retainCount标识当前对象有几个所有权,任何一个对象都有一个或多个拥有者。对象的结构:对象存在一块内存空间保存对象,这块内存空间还留有8个字节的存储空间存储retainCount
(3)引用计数器的作用
引用计数器来判断对象要不要回收。当引用计数器的值为0时表示该内存空间需要回收,当引用计数器的值为1时表示该内存空间还有对象需要用,不需要回收。有个例外:当对象的值为nil时,count等于0,但是此时不回收,Person *P=nil,未分配空间就不存在回收内存空间的说法。
(4)对引用计数器操作
retain消息,使得count的值加1;release消息使得count的值减1,并不代表释放对象;retainCount消息获得当前对象引用计数器的值。
(4)对象的销毁
当对象被销毁,系统就向对象发送一条dealloc消息,一般重写dealloc方法,在这里释放相关资源。重写dealloc方法调用[super dealloc],一般房子代码块最后调用。dealloc方法代码块如下:


-(void)dealloc{
NSLog(@"当前代码块已被释放");
[super dealloc];
}


注意:
(1)count不等于0,不会回收,除非程序退出。
(2)alloc、new、copy创建对象,count等于1;
(3)系统会自动调用dealloc方法,不能yoga对象去调用dealloc方法。


2、内存管理的分类

(1)Mannu Reference Counting(MRC,手动管理)。
(2)Automatic Reference Counting(ARC,自动引用计数)
(3)Garbage Collection(垃圾回收),ios不支持垃圾的回收。
我们创建项目时默认的是ARC。


手动内存管理的示例

#import <Foundation/Foundation.h>
//定义了一个类Person
@interface Person : NSObject
@end
@implementation Person
-(void)dealloc{
//先释放子类的
NSLog(@"当前代码块已被释放");
//再释放父类的
[super dealloc];
}
@end

int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p=[Person new];
//引入计数器count为1
NSUInteger count = [p retaincount];
//count =2
person *p2=[p retain];
//count = 1
[p release];
//count = 0,p的空间被释放
[p release];
}
return 0;
}


三 内存管理的原则和研究的内容

1、内存管理的原则

a 有人在使用对象,对象不会被回收
b 需要使用对象时让retainCount加1
c 不想使用这个对象时让retainCount减1
d 谁创建,谁release,才能保证对象能够释放
e 谁retain谁release
总结:有始有终。


2、内存管理研究的内容

野指针
(1)定义的指针变量未初始化会造成野指针
(2)指针指向的内存空间已经释放会造成野指针
内存泄露
内存泄露即对象没有指针指向,但依然存在内存,就是内存的泄露。就是栈区的指针被释放,而堆区的内存空间没有释放。


四 单个对象内存管理和多个对象内存管理

1、单个对象内存管理

#import <Foundation/Foundation.h>
@interface Person : NSObject
-(void)run;
@end
@implementation Person
-(void)dealloc{ NSLog(@"当前代码块已被释放"); [super dealloc]; }
-(void)run{
NSLog(@"人正在跑");
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p=[Person new];
NSUInteger count = [p retaincount];
[p run];
[p release];//count = 0,p被释放
//还能调用run方法,因为释放只是标记此空间无占用,空间还存在,还没有其他程序占用,还有值存在,但是这种调用是不正确的
[p run];
//如果一个对象已被释放,则此时指针就是野指针,不能被调用
//以下的调用都是错误的
[p run];
[p retain];//不能让对象再生
[p release];
[p retainCount];
}
return 0;
}


空指针:未指向任何东西的指针
(1)nil:对象的值为nil
(2)Nil:类的值为nil
(3)NULL:是一个通用指针
(4)[NSNULL null]对象的指针,用在不能使用nil的地方
避免使用僵尸指针的方法
(1)对象释放了以后给对象赋值为nil,因为给nil发送任何消息,都没有效果
(2)d=nil后提高了程序的健壮性


单个对象的内存泄露问题

(1)只创建不使用

//只创建不使用,内存泄露
Person *p=[Person new];


(2)未遵守内存管理的原则

Person *p=[Person new];//count = 1
[p retain];//count = 2
//并没有释放
4000
,内存泄露
[p release];//count = 1


(3)不正当使用nil

Person *p=[Person new];
p=nil;
[p release];//p是nil不会有任何操作,内存得不到释放


(4)在方法中对传入的对象进行了retain

-(BOOL)run:(Person *)person{
[p retain];//count = 2
return YES;
}
Person *p=[Person new];
[p run:p];
[p release];//count = 1,内存未释放,泄露问题存在


2、多个对象内存管理

多个对象内存管理的三个问题

(1)两个不同类型的包含关系问题

//关键点是让count加1
//只需完成以下代码块
-(void)setCar:(Car *)car{
//让count加1
_car=[car retain];
}
-(void)dealloc{
//让_car销毁
[_car release];
[super dealloc];
}


(2)两个相同类的问题

//关键点:创建新类之前,让旧类销毁
//完成以下代码块
-(void)setCar:(Car *)car{
//release旧值
[_dog release];
//让retain新值
_car=[car retain];
}
-(void)dealloc{
//让_car销毁
[_car release];
[super dealloc];
}


(3)同类同名的问题

//关键点就是同名的话,就不需要release
//完成以下代码块
-(void)setCar:(Car *)car{
if(_car!=car){
//release旧值
[_dog release];
//让retain新值
_car=[car retain];
}
}
-(void)dealloc{
//让_car销毁
[_car release];
[super dealloc];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  内存管理 ios oc