OC内存管理初级

一、内存管理的方式

***整个iOS内存管理的核心是:引用计数。

     1C语言的内存管理,管理内存的开辟(malloc)和回收(free

     2、但是OCC语言不一样,不直接管理内存的开辟和回收。管理的是引用计数。通过控制引用计数的加减,来实现内存管理,是一种间接管理内存的方式。

     引用计数从01表示开辟了内存空间,10表示内存空间被系统回收了。

     3、我们所谓的内存管理,其实就是管理的引用计数的加和减


(一)垃圾回收(gc)Garbage Collection

程序员只需要开辟内存空间,不需要用代码显示地释放,系统来判断哪些空间不再被使用,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何代码,由系统自动完成垃圾回收。Java开发中一直使用的就是垃圾回收技术。

(二)MRC(Manual Reference Count)

引用计数:OC采用引用计数机制管理内存当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减当引用计数到零时,该对象就将释放占有的资源

人工引用计数:内存的开辟和释放都由程序代码进行控制。相对垃圾回收来说,对内存的控制更加灵活,可以在需要释放的时候及时释放,对程序员的要求较高,程序员要熟悉内存管理的机制。

1、+alloc:开辟内存空间,让被开辟的内存空间的引用计数变为1。这是0到1的过程

此方法是继承自NSObject的方法,用于创建对象,给开辟的堆区域空间清0,同时将对象的引用计数设置为1,是对象引用计数从01得过程。

    <span style="font-size:14px;">Person *p = [[Person alloc] init];
    
    //NSObject这个类提供了一个查看对象引用计数的方法
    //- (NSInteger)retainCount;
    NSLog(@"p的引用计数为%lu,p:%p %p",[p retainCount],p,&p);
    
    //alloc是重新开辟空间,所以只要是alloc创建出来的对象,引用计数此时肯定是1
    Person *p1 = [[Person alloc] init];
    NSLog(@"p1的引用计数为%lu,p1:%p",[p1 retainCount],p1);</span>

dealloc

<span style="font-size:14px;">- (void)dealloc{
    NSLog(@"%@被释放了",self);
    [super dealloc];
}</span>


2、-retain这个方法也是继承自NSObject,他的作用是将receiver(对象)的引用计数加1,并且返回receiver(对象)的首地址


   <span style="font-size:14px;"> [p retain];
    NSLog(@"p的引用计数为%lu,p:%p %p",[p retainCount],p,&p);
    
    Person *p3 = [p retain];
    NSLog(@"p3的引用计数为%lu,p3:%p %p",[p3 retainCount],p3,&p3);</span>

 3、-copy这个方法也是继承自NSObject的,作用是拷贝一个 receiver 的副本,receiver所对应的对象引用引用计数保持不变,副本的引用计数设置为1,返回副本的首地址。

      并不是所有的对象都能接收copy消息,只有接受了NSCopying协议,并且实现了copyWithZone:方法的对象才能接收copy消息,否则就会出现异常。

"main.h":

 Student *stu = [[Student alloc]initWithName:@"zhangsan" age:18 gender:@"男"];
    [stu retain];
    NSLog(@"stu 引用计数是%lu, stu = %p",[stu retainCount],stu);
    
    Student *stu1 = [stu copy];


//伪拷贝,相当于直接赋值,并没有生成新的拷贝对象
- (id)copyWithZone:(NSZone *)zone{
    return [self retain];
}

//真拷贝之浅拷贝
- (id)copyWithZone:(NSZone *)zone{
    Student *student = [[Student alloc]initWithName:self.name age:self.age gender:self.gender];
    return student;
}

//真拷贝之深拷贝
//两个对象,两份内容
- (id)copyWithZone:(NSZone *)zone{
    Student *student = [[Student alloc]initWithName:[self.name copy] age:self.age  gender:[self.gender copy]];
    return student;
}


 4、-release此方法是继承NSObject的,作用是让receiver所对应的对象的引用计数减1,无返回值

    一般来说,谁的引用计数增加,谁就需要执行release让其引用计数减少。

<span style="font-size:14px;">[p release];
   //p = nil;
    
    NSLog(@"p的引用计数为%lu,p:%p %p",[p retainCount],p,&p);
    NSLog(@"p3的引用计数为%lu,p3:%p %p",[p3 retainCount],p3,&p3);
    
    [p release];
    [p release];
    NSLog(@"p的引用计数为%lu,p:%p %p",[p retainCount],p,&p);</span>

(*)当一个对象的引用计数降到0的时候,注意此时retainCount打出来的值并不是0,而是1,不过此时对象已经被释放了。如果再去访问被释放的内存空间就会造成crash,也就是野指针。当对象的引用计数到0,内存回收之前,系统会自动执行该类的dealloc方法。

(*)野指针引发的崩溃有时有,有时没有。如果被释放的内存区域没有被使用,访问是不会出现问题的,但是一旦这块被回收的内存空间被使用了,再去访问就会出现异常。

5、-autorelease

    //如何用NSMutableArray实现队列的管理方式

    **栈:添加元素我们采用addObject:,删除元素我们采用的是removeLastObject方法,达到先进后出得效果。

/*
     while(arr[count] != 0){
     [[arr lastObject] release];
     [arr removeLastObject];
     }
     */

    **队列:只不过把方法改成 removeObjectAtIndex:0就可以了

Person *p1 = [[Person alloc]init];
    Person *p2 = [[Person alloc]init];
    [p1 retain];
    [p1 retain];
    
    [p2 retain];
    NSLog(@"p1引用计数为 %lu,p2引用计数为%lu, %p, %@",[p1 retainCount],[p2 retainCount],p1,p2);

   (**)[[NSAutoreleasePool alloc]init] [pool release]可以看作是一个括号,在括号里面向对象发送autorelease消息,此时被pool管理

   (**)pool先记下,都是谁执行了autorelease消息(就像可变数组一样,将接收autourelease消息的对象逐一加到pool里面)

   (**)pool不再需要的时候(销毁),会向pool中记录的receiver(倒序)发送一个release消息


//初始化一个池子
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    [p1 autorelease];
    NSLog(@"p1引用计数为 %lu,p2引用计数为%lu, %p, %@",[p1 retainCount],[p2 retainCount],p1,p2);

    [p1 autorelease];
    NSLog(@"p1引用计数为 %lu,p2引用计数为%lu, %p, %@",[p1 retainCount],[p2 retainCount],p1,p2);

    [p1 autorelease];
    NSLog(@"p1引用计数为 %lu,p2引用计数为%lu, %p, %@",[p1 retainCount],[p2 retainCount],p1,p2);

    [p2 autorelease];
    NSLog(@"p1引用计数为 %lu,p2引用计数为%lu, %p, %@",[p1 retainCount],[p2 retainCount],p1,p2);
    
    [p2 autorelease];
    
    //释放池子
    [pool release];


@autoreleasepool {
        [p1 autorelease];
        [p1 autorelease];
        [p1 autorelease];
        
        [p2 autorelease];
        [p2 autorelease];
    }



(三)ARC(Auto Reference Count)

自动引用计数:iOS 5.0的编译器特性,它允许用户只开辟空间,不用去释放空间。它不是垃圾回收!

它的本质还是MRC,只是编译器帮程序员默认加了释放的代码。

(四)iOS的内存管理

   iOS支持两种内存管理方式:ARC和MRC。

   MRC的内存管理机制是:引用计数。  

   ARC是基于MRC的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值