黑马程序员——OC笔记之内存管理

------- android培训java培训iOS培训.Net培训、期待与您交流! ----------

为什么要内存管理?

移动设备的内存及其有限,每个app所能占用的内存是有限制的。当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要使用的内存空间。否则程序会卡死,甚至崩溃。因此必须学会内存管理。

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

MannulReference Counting(MRC,手动管理, iOS4.1之前的版本)

automatic reference counting(ARC,自动引用计数,iOS4.1 之后推出的)

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

ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;

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

内存管理的范围:

任何继承了NSObject的对象(所有的OC对象,对象类型)

对其他非对象类型(基本数据类型)无效(int、char、float、double、struct、enum等)

只有OC对象才需要进行内存管理的本质原因:

因为OC对象存放于堆里面,非OC对象一般放在栈里面(栈内存会被系统自动回收)

内存管理的原理:

在每个对象内部,都有一个4个字节的引用计数器,表示“对象的引用个数”,当用newalloccopy创建一个新对象后,计数器的值为1。当对象调用retain方法时,计数器加1当调用release方法是,计数器减1当计数器的值减为0后,对象会被回收。在对象被销毁之前,系统会向对象发送一条dealloc消息,此时系统就会帮我们释放该对象所占用的内存。

1、引用计数器的常见操作

给对象发送一条retain消息, 可以使引用计数器值+1(retain方法返回对象本身)

Person *p = [Person alloc]init];
[p retain];

给对象发送一条release消息, 可以使引用计数器值-1

[p release];

给对象发送retainCount消息, 可以获得当前的引用计数器值(通过%ld输出查看)

NSLog(@"p->retainCount = %ld",p.retainCount);

注意: release并不代表销毁\回收对象, 仅仅是计数器-1

我们只能通过操作对象计数器,间接控制对象的释放与否。

以上这些操作必须在关闭ARC的情况下才能使用,Xcode默认是开启ARC。

2、关闭ARC:

1.设置项目信息


2.设置ARC为NO


3、判断对象是否被回收

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

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

-(void)dealloc
     {
          [_car release];
          [super dealloc];
      }

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

2)一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)。为了防止调用出错,可以将“野指针”指向nil(0)。 

Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject 
@property int age;
@end
Person.m
#import "Person.h" 
@implementation Person
//监测对象是否被回收的方法
-(void)dealloc{
//释放子类对象
NSLog(@"对象被销毁了~"); 
//释放父类
[super dealloc];
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        //用Person 类实例化一个实例对象
        Person *p = [Person new];  // 对象有没有所有者?  有
        
        //证明有一个所有者
        NSUInteger count = p.retainCount;
        NSLog(@"count = %lu",count);  // 1
        
        //使用引用计数器+1
        [p retain];
        NSLog(@"p.retainCount = %lu",p.retainCount);   //2
        
        //如果要回收对象? 应该想办法 retatinCount = 0
        [p release];
        NSLog(@"p.retainCount = %lu",p.retainCount);   //1
        
        [p release];  //此处执行后,p的空间被回收           //0
        //证明p的空间被释放了,可以在在Person类中,重写dealloc方法
    }
    return 0;
}


内存管理的原则

1)原则

只要对象还有人在使用,那么这个对象就不会被回收;只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;当你不想使用这个对象时,应该让对象的引用计数器-1;

2)“谁污染,谁治理。谁开发,谁保护”,跟这句口号一样,内存是,谁创建,谁release。谁retain,谁release。

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

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

单个对象的内存管理(野指针)

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

僵尸对象:所占内存已经被回收的对象,僵尸对象不能再被使用。(默认情况下xcode为了提高编码效率,没有开启僵尸对象检测)

Person *p = [Person alloc]init];// 1
[p release];                    // 0
//此时p为野指针,也称之为僵尸对象
[p run];//野指针访问
[p retain];//僵尸对象死而不能复生

打开僵尸对象检测



为避免不小心调用僵尸对象,可以将对象赋值nil
Person *p = [Person alloc]init];// 1
[p release];                    // 0

p = nil;
[p run];//相当于[nil retain],空指针调用方法无反应
[p retain];//相当于[nil retain],不会报错,但应避免

多个对象内存管理(野指针)

举个栗子��
小刘开车去拉萨
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
       
        Person *p = [[Person alloc]init];// 1
        Car *bmw=[Car new];// 1
        bmw.speed=80;
//        [p setCar:bmw];//可以用点语法替换
        p.car=bmw;
        NSLog(@"bmw retainCount=%lu",[bmw retainCount]);
        
        [p goLasa];
        [p goLasa];
        
        [bmw release];//_car--->1
        NSLog(@"bmw retainCount=%lu",[bmw retainCount]);

//        [bmw release];//将此句放在人的dealloc方法里,可以让车先于人亡,同时不影响人的方法的调用,否则会出现人没车还能开车的不合理现象
        [p goLasa];
        
        [p release];
        
        
    }
    return 0;

Car.h
#import <Foundation/Foundation.h>

@interface Car : NSObject
{

    int _speed;
}
-(void)setSpeed:(int)speed;
-(void)run;
@end

Car.m
@implementation Car
- (void)dealloc
{
    NSLog(@"车已经毁了");
    [super dealloc];
}
-(void)setSpeed:(int)speed{

    _speed=speed;
}
-(void)run{

    NSLog(@"小明正开车在以%d码的速度去拉萨",_speed);
}
@end

Person.h
#import <Foundation/Foundation.h>
#import "Car.h"
@interface Person : NSObject
{

    Car *_car;
}
-(void)setCar:(Car*)car;
-(void)goLasa;
@end

Person.m
#import "Person.h"

@implementation Person
- (void)dealloc
{
    [_car release];//在人挂掉之前让车报废 _car--->0
    
    NSLog(@"人已经挂了");
    [super dealloc];
}
-(void)setCar:(Car*)car{
    
    _car=[car retain];//_car--->2
}
-(void)goLasa{

    [_car run];
    
}
@end


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值