zoukankan      html  css  js  c++  java
  • 第三讲:ObjC 内存管理1 黄金法则

    转:http://tigercat1977.blog.163.com/blog/static/2141561122012111293337435/

    第三讲:Obj-C 内存管理1 - 黄金法则 

     
    主要内容
          OC内存管理原理
          OC内存管理相对 C/C++ 有何好处
          OC内存管理的 alloc, retain, release
          遛狗原则
          OC 对象生命周期

    内存管理  黄金法则
          The basic rule to apply is Everything that increases the refernce counter with alloc,
    [mutable] copy [Whith Zone:] or retain is charge of the corresponding [auto] release.

          如果对一个对象使用了  alloc, [mutable] copy, retain, 
    那么你必须使用相应的 release 或者 autorelease


    内存管理类型定义

         基本类型   任何 C 的类型,如:
         int,  short,  char,  long,  long long,  struct,  enum,  union 等属于基本类型或者结构体
         内存管理对于 C 语言基本类型无效

         OC类型 (非基本类型)
         任何继承于 NSObject 类的对象都属于 OC 类型
         也就是除了 C 之外的其他类型

    OC 对象结构
    第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

    C / C++ 内存管理原理
    第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

    C / C++ 内存管理代码
          Int *p1 = malloc(100);
          Int *p2 = p1;
          Int *p3 = p1;
          Free(p2);

          Free(p2);

    内存管理对象
          对于OC的对象,非基本对象(int,  short, struct)
          NSObject, 凡是继承于 NSObject
          每一个对象都有一个 retainCount 计数器。表示当前的被应用的计数器。如果计数为0,那么就真正的释放这个对象

    内存管理图示
          这就是引用计数的理论。在实际应用中,通过只有两个原因我们才会创建一个对象:
              1. 作为一个实例变量保留。
              2. 在函数内部作为临时变量使用。
          大多数情况下,一个实例变量的设置器(setter)会自动释放(autorelease)
          原来引用的对象,同时保留(retain)新的。你只需要保证在 dealloc 函数中释放(release)了它就行了。
    第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

    遛狗原理
    第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

    OC内存管理
    第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

    alloc retain release 函数
          alloc 函数是创建对象使用,创建完成后计数器为 1
          只用一次

          retain 是对一个对象的计数器 +1
          可以调用多次

          release 是对一个对象计数器 -1
          减到 0 对象就会从内存中释放

    OC内存管理
          Objective - C 类中实现了引用计数器,对象知道当前被引用了次数。
          最初对象的计数器是 1 。
          如果需要引用对象了,可以给对象发送  release 消息,这样对象计数器就加 1。
          当不需要引用对象了,可以给对象发送  release 消息,这样对象计数器就减 1。
          当计数器减到 0,自动调用对象的 dealloc 函数,对象就会释放内存。
          计数器为 0 的对象不能再使用 release 和其他方法 。

    retain / release 例子
          NSMutableString *str = [[NSMutableString alloc] init];
                                          // str 计数器为 1
          [str retain];                // str 计数器为 2
          [str retain];                // str 计数器为 3
          [str release];              // str 计数器为 2
          [str release];              // str 计数器为 1
          [str release];              // str 计数器为 0,   对象释放内存
       
    内存管理总结
    Objective - C 的内存管理机制与 .Net / Jave 那种全自动的垃圾回收机制是不同的,它本质上还是 C 语言中的手动管理方式,只不过稍微加了一些自动方式。
          Objective - C 的内存管理是基于引用计数的。要做的事情只是关注的引用,而释放内存的工作实际上由运行环境完成。
          在最简单的情形中,分配的(alloc)对象,或者是保留(retain)在一些地方的对象,都需要发送一个 release 消息。这也意味着,如果使用了一次 alloc,然后又 retain 了一次,那你需要 release 两次才能释放对象的内存。

    下面三种增加对象技术器
          1. 当明确的使用 alloc 方法来分配对象。
          2. 当明确的使用 copy [WithZone:] 或者 murableCopy[WithZone:] 来 copy 对象时。
          3. 当明确使用 retain 消息。

          上述三种方法使得计数器增加,那么就需要使用 [auto] release 来明确释放对象,也就是递减计数器。

    遛狗原则举例 (一只狗时)这方法不够完善

    // Dog.h #import <Foundation/Foundation.h> @interface Dog : NSObject { int _ID; } @property int ID; @end

    // Dog.m #import "Dog.h" @implementation Dog @synthesize ID = _ID; - (void) dealloc { NSLog(@"dog %d is dealloc", _ID); [super dealloc]; } @end


    // Person.h #import <Foundation/Foundation.h> #import "Dog.h" @interface Person : NSObject { Dog *_dog; } - (void) setDog:(Dog *)aDog; - (Dog *) dog; @end

    // Persen.m

    @implementation Person - (void) setDog:(Dog *)aDog { if (aDog != _dog) { // _dog = aDog; // [_dog retain]; _dog = [aDog retain]; // 让计数器 +1 } } - (Dog *) dog { return _dog; } - (void) dealloc { NSLog(@"person is delloc"); // 把人拥有的 _dog 释放 [_dog release]; [super dealloc]; } @end


    // main.m #import <Foundation/Foundation.h> #import "Dog.h" #import "Person.h" int main (int argc, const char * argv[]) { @autoreleasepool { NSLog(@"Hello, World!"); Dog *dog1 = [[Dog alloc] init]; [dog1 setID:1]; Person *xiaoLi = [[Person alloc] init]; // 小丽要遛狗 [xiaoLi setDog:dog1]; Person *xiaoWang = [[Person alloc] init]; [xiaoWang setDog:dog1]; NSLog(@"dog1 retain count1 is %ld", [dog1 retainCount]); // 输出:dog1 retain count1 is 3 [dog1 release]; NSLog(@"dog1 retain count2 is %ld", [dog1 retainCount]); // 输出:dog1 retain count2 is 2 [xiaoWang release]; NSLog(@"dog1 retain count3 is %ld", [dog1 retainCount]); // 输出:person is delloc // :dog1 retain3 count is 1 [xiaoLi release]; // 输出:person is delloc // :dog 1 is dealloc } return 0; }


    遛狗原则举例2 (两只狗时)这方法比较完善

    // Dog.h #import <Foundation/Foundation.h> @interface Dog : NSObject { int _ID; } @property int ID; @end

    // Dog.m #import "Dog.h" @implementation Dog @synthesize ID = _ID; - (void) dealloc { NSLog(@"dog %d is dealloc", _ID); [super dealloc]; } @end


    // Person.h #import <Foundation/Foundation.h> #import "Dog.h" @interface Person : NSObject { Dog *_dog; } - (void) setDog:(Dog *)aDog; - (Dog *) dog; @end

    // Persen.m

    @implementation Person - (void) setDog:(Dog *)aDog { if (aDog != _dog) {

    [_dog release]; // 要注意的地方,提前 release _dog = [aDog retain]; // 让计数器 +1 } } - (Dog *) dog { return _dog; } - (void) dealloc { NSLog(@"person is delloc"); // 把人拥有的 _dog 释放 [_dog release]; [super dealloc]; } @end


    // main.m #import <Foundation/Foundation.h> #import "Dog.h" #import "Person.h" int main (int argc, const char * argv[]) { @autoreleasepool { Dog *dog1 = [[Dog alloc] init]; [dog1 setID:1]; Dog *dog2 = [[Dog alloc] init]; [dog2 setID:2]; Person *xiaoLi = [[Person alloc] init]; // 小丽要遛狗 [xiaoLi setDog:dog1]; [xiaoLi setDog:dog2]; NSLog(@"dog1 retain count is %ld", [dog1 retainCount]); //输出:dog1 retain count is 1 [dog1 release]; //输出:dog 1 is dealloc NSLog(@"dog2 retain count is %ld", [dog2 retainCount]); //输出:dog2 retain count is 2 [xiaoLi release]; //输出:person is delloc NSLog(@"dog2 retain count is %ld", [dog2 retainCount]); //输出:dog2 retain count is 1 [dog2 release]; //输出:dog 2 is dealloc } return 0; }

  • 相关阅读:
    Sonar系列:IDEA集成SonarLint(二)
    Jenkins 安装部署全过程
    使用Docker搭建Sonarqube
    Sonar系列:SonarQube+SonarScanner 最全安装步骤(一)
    微信小程序反编译解包教程
    一张图告诉你,如何攻击Java Web应用
    windows server2019共享文件配额报错The quota limit is 10240.00 MB and the current usage is 10213.39 MB (99% of limit)的处理
    jenkins使用ssh remote插件执行shell后无法退出的问题处理
    基于docker镜像centos:7 镜像制作自定义的centos及tomcat/php/nginx镜像
    centos7.9环境基于docker和pipeline构建jenkins的ci平台
  • 原文地址:https://www.cnblogs.com/jackljf/p/3589253.html
Copyright © 2011-2022 走看看