• OC-7-内存管理


    课程要点:

    • 内存管理的必要性
    • MRC(手动管理)
    • 自动释放池
    • ARC是怎么对内存进行管理的

        内存管理的必要性

       OC是一门面向对象的语言,在软件运行过程中会创造大量的对象,每创建一个对象系统就会给其分配一块内存,如果开发者不对创建的这些对象进行管理,当这个软件占用系统20兆内存时,iPhone开始发出内存警告,如果占用30兆内存时,iPhone OS会关闭应用程序。为了避免这种情况我们需要对咱们创建的对象进行管理。管理方式有MRC(手动管理)、ARC(自动管理)。

        MRC在11年以后,渐渐的被开发者所抛弃,但为什么开发者还要学习这个东西呢。举个例子,就好比小时候家里的各种物品一般都是母亲进行整理,我们基本上很少管这些事,但我们多多少少都知道母亲整理物品的习惯,我们需要找什么东西时,只要按照母亲的习惯去找就行。如果一点都不知道母亲整理物品的习惯,这对我们找东西将会很麻烦。

         在比较正规的公司,他们对项目的要求是很严格的。项目做完他们会对你做的项目进行一个内存检测,如果过高,他们会让你进行重构,此时如果你不知道你的项目是怎么管理内存的,那不是就是抓瞎么。

       MRC

       在WWDC2011和iOS5之前,苹果开发者一直都在使用MRC进行内存管理。

        因为现在Xcode创建的工程默认都是由ARC管理的。所以在使用MRC之前要关闭ARC,如图所示

         

         转过MRC后看代码:

         PS:我之前已经创建过Person类,所以采用下面代码之前先在你项目里新建一个Person类

    #import <Foundation/Foundation.h>
    #import "Person.h"
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
        /*    object-c 使用引用计数的方式管理内存。当我们使用一个指针指向一块内存的时候,应该对这块内存做retain操作,那么引用计数加一。当我们不再使用这个指针指向这块内存,应该对这块内存做release操作,那么引用计数减一。这样可以使引用计数值一直保持等于指向这块内存的指针数量。retainCount返回当前内存的引用计数值。当内存被开辟后,默认的引用计数为1 。
         */
    
            
        //产生一个新的对象,此时不用release,因为新建的对象引用为1,不需要为第一个指向这个对象的指针额外加一计数。
        Person *person1 = [[Person alloc]init];
            
        NSInteger count = [person1 retainCount];
            
        //赋值后count等于1
        NSLog(@"%ld",count);
        
        
        NSObject *person2 = person1;
            
        [person2 retain];
            
        count = [person2 retainCount];
            
        //赋值后count等于2
        NSLog(@"%ld",count);
            
        //需要认识的是,不论使用object1还是object2调用retain方法都是一样的,因为两者指向同一块内存,计数增加减少都是以内存为对象的
        [person1 release],person1 = NULL;
            
        //当object2 release之后,这个对象的引用计数为0,内存被释放,同时会调用这个对象的delloc方法。delloc方法是每一个类都有的隐式方法。当用这个类创建的对象的retainCount为0的时候才会调用,自己可以在.m文件中将他重写.如果此时你打印retainCount你会发现他的值依然是1,这里大家只需要记住系统内部会对咱创建的对象进行操作,才会造成这种现象。不必深究。
        [person2 release],person2 = NULL;
            
               
    /* * object release 之后为什么还要把对象给置空 因为对象其实就是一个指针,指针指向的是一块内存,release仅仅是把这个内存释放了,也就是说release以后系统把这块内存给回收了。但此时指针指向得还是这块内存。这是不符合逻辑的,所有我要把指针给置空,至此才切断了这个指针与对象的所有关系。 */ } return 0; }

          输出结果:

    2015-11-27 17:47:32.162 Test[2333:228117] 1
    2015-11-27 17:47:32.163 Test[2333:228117] 2
    Program ended with exit code: 0
    

      

        重写Person.m里的delloc方法

    #import "Person.h"
    
    @implementation Person
    
    //这是一个隐式方法,也就是苹果在内部已经声明和实现好了,如果我想要使用直接调用便可,如果想改变里面的内容,只需在.m里面把他重写就行。
    - (void)dealloc{
        
        NSLog(@"person对象被释放");
        
        [super dealloc];
        
        /*
         * 为什么需要调用父类的dealloc方法
         
           子类的某些实例是继承自父类的。因此,我们需要调用父类的dealloc方法,来释放父类拥有的这些对象。
         
           PS:每一个类都有一个父类,用到这个类时不可避免的会用到父类里面的东西,所以咱们在子类里释放内存的时候,要记得通过[super dealloc]来释放掉咱们用到的父类里面的对象。
         
           调用的顺序一般来说调用的顺序是,当子类的对象释放完时,然后再释放父类的所拥有的实例。
         
         */
    }
    
    @end

       输出结果:

    2015-11-27 18:13:32.355 Test[2403:238207] 1
    2015-11-27 18:13:32.356 Test[2403:238207] 2
    2015-11-27 18:13:32.356 Test[2403:238207] person对象被释放
    Program ended with exit code: 0

       自动释放池:

      1、Autorelease pool

      自动释放池(Autorelease pool)是OC的一种内存自动回收机制,可以将一些临时变量通过自动释放池来回收统一释放

      自动释放池本事销毁的时候,池子里面所有的对象都会做一次release操作

      2、autorelease

      任何OC对象只要调用autorelease方法,就会把该对象放到离自己最近的自动释放池中(栈顶的释放池)。

         

           自动释放池的使用

            //ios5.0新方式

            @autoreleasepool

           {

                //池的区域

           }

            //ios5.0之前的老方式

           NSAutoreleasePool *pool=[[NSAutoreleasePool alloc]init];

               //池的区域

           [pool release];

           自动释放池使用技巧:

           PS:已重写person.m的delloc方法,并在里面写上NSLog(@"person对象已释放");如果delloc方法执行,便会有输出。

    int main(){
        
        //在MRC中并不是将ARC的代码放在池中便能够自动管理内存,每创建一个对象都有在后面加上autorelease
        NSAutoreleasePool *pool=[[NSAutoreleasePool alloc]init];
        
        //不加autorelease,出池后person.m的delloc方法不会执行
        Person *person = [[Person alloc]init];
        
        [pool release];
        
    }

          此时控制台输出:

    Program ended with exit code: 0

         

    int main(){
        
        //在MRC中并不是将ARC的代码放在池中便能够自动管理内存,每创建一个对象都有在后面加上autorelease
        NSAutoreleasePool *pool=[[NSAutoreleasePool alloc]init];
        
        //创建对象时在后面加上autorelease,出池后,person.m里delloc方法执行
        Person *person = [[[Person alloc]init] autorelease];
        
        
        [pool release];
        
    }

         此时控制台输出:

       

    2015-11-29 14:55:02.287 Test[2757:93300] person对象被释放
    Program ended with exit code: 0

        

         以上是个人见解,若有错误欢迎指正,在学习中若有不理解欢迎骚扰 QQ:2314858225

     

  • 相关阅读:
    文件权限
    函数指针
    位操作
    宏定义
    GNU gcc常用编译选项
    SHELL编程(六)---------数组和函数
    26.使用中间件的方式包装日志输出
    25.最基本的日志输出方式,内置日志包使用
    24.把熔断器整合到我们的客户端代码中(初步)
    23.熔断器学习,熔断器的三种状态,状态获取
  • 原文地址:https://www.cnblogs.com/g-ios/p/5001555.html
Copyright © 2020-2023  润新知