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

——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
//并没有释放,内存泄露
[p release];//count = 1

(3)不正当使用nil

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

(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];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值