zoukankan      html  css  js  c++  java
  • 自动引用计数

    1.1 什么是自动引用计数

    自动引用计数是指内存管理中对引用采取自动计数的技术

    1.2 内存管理/引用计数

    生成并持有对象:alloc/new/copy/mutableCopy

    持有对象:retain

    释放对象:release

    废弃对象:dealloc

    自己生成的对象,自己所持有:

    id obj = [[NSObject alloc] init]; // 指向 生成并持有对象的指针 被赋值给变量obj

    非自己生成的对象,自己也能持有:

    id obj = [NSMutableArray array]; // 取得的对象存在,但自己不持有对象  NSMutableArray类对象被赋值给obj,但变量obj自己并不持有该对象

    [obj retain]; // 使用retain方法可以持有对象

    不在需要自己持有的对象时释放:

    id obj = [[NSObject alloc] init]; // 自己生成并持有对象

    [obj release]; // 释放对象

    用某个方法生成对象,并将其返回给该方法的调用方:

    - (id) allocObject {

        id obj = [[NSObject alloc] init];

        return obj;

    }

    原封不动地返回用alloc方法生成并持有的对象,就能让调用方也持有该对象。

    调用[NSMutableArray array]使取得的对象存在,但自己不持有对象:

    - (id)object {

       id obj = [[NSObject alloc] init];

       [obj autorelease];

       return obj;

    }

    使用了autorelease方法,可以使取得的对象存在,但自己不持有对象。

    release:立即释放

    autorelease:不立即释放,注册到autoreleasepool中,pool结束时自动调用release方法

    无法释放非自己持有的对象:

    id obj = [NSObject object]; // 取得的对象存在,但自己不持有对象

    [obj release]; // 释放非自己持有的对象,应用程序崩溃

    苹果采用散列表(引用计数表)来管理引用计数

    引用计数表各记录中存有内存块地址,可从各个记录追溯到各对象的内存块

    1.3 ARC规则

    id obj = [[NSObject alloc] init]; // id 和  对象类型在没有明确指定所有权修饰符时,默认为__strong修饰符 等同于 id __strong obj = [[NSObject alloc] init];

    ARC:

    {

      id __strong obj = [[NSObject alloc] init];

    }

    // 此源代码明确指定了C语言的变量的作用域

    MRC:

    {

      id obj = [[NSObject alloc] init];

      [obj release];

    }

    // 为了释放生成并持有的对象,增加了 release 方法;该源代码进行的动作同ARC的动作完全一样

    附有__strong修饰符的变量obj在超出其变量作用域时,即在该变量被废弃时,会释放其被赋予的对象

    {

      // 自己生成并持有对象

      id __strong obj = [[NSObject alloc] init];

    }

     // 因为变量obj超出其作用域,强引用失效,所以自动地释放自己持有的对象

    通过__strong 修饰符,不必再次键入retain或者release,完美地满足了“引用计数内存管理的思考方式”:

        自己生成的对象,自己所持有

        非自己生成的对象,自己也能持有

        不再需要自己持有的对象时释放

        非自己持有的对象无法释放

    @interface Test : NSObject

    {

        id __strong obj_;

    }

    - (void)setObject:(id __strong)obj;

    @end

    @implementation Test

    - (id)init

    {

       self = [super init];

       return self;

    }

    - (void)setObject:(id __strong)obj 

    {

       obj_ = obj;

    }

    @end

    循环引用:

    {

       id test0 = [[Test alloc] init]; // 对象A   test0持有Test对象A的强引用

       id test1 = [[Test alloc] init]; // 对象B   test1持有Test对象B的强引用

       [test0 setObject:test1]; // 对象A的obj_成员变量持有对象B的强引用 

       [test1 setObject:test0]; // 对象B的obj_成员变量持有对象A的强引用

    }

    // test0变量超出其作用域,强引用失效,所以自动释放对象A

    // test1变量超出其作用域,强引用失效,所以自动释放对象B

    // 此时,持有对象A的强引用的变量为  对象B的obj_ ; 持有对象B的强引用的变量为 对象A的obj_

    // 发生内存泄漏

    // 循环引用很容易发生内存泄漏 <内存泄漏就是应当废弃的对象在超出其生存周期后继续存在>

    __weak 修饰符提供弱引用,弱引用不能持有对象实例

    id __weak obj = [[NSObject alloc] init]; // 编译器对此会给出警告⚠️

    // 此源代码将自己生成并持有的对象赋值给附有__weak修饰符的变量obj。即变量obj持有对持有对象的弱引用。因此,为了不以自己持有的状态来保存自己生成并持有的对象,生成的对象会立即被释放

    id __unsafe_unretained obj = [[NSObject alloc] init]; // ⚠️

    __unsafe_unretained修饰符同__weak一样,因为自己生成并持有的对象不能继续为自己所有,所以生成的对象会立即被释放

    __unsafe_unretained修饰的变量既不持有对象的强引用也不持有对象的弱引用

    @autoreleasepool {

        id __autoreleasing obj = [[NSObject alloc] init];

    }

  • 相关阅读:
    编译原理-第二章 一个简单的语法指导编译器-2.4 语法制导翻译
    编译原理-第二章 一个简单的语法指导编译器-2.3 语法定义
    编译原理-第二章 一个简单的语法指导编译器-2.2 词法分析
    LeetCode 1347. Minimum Number of Steps to Make Two Strings Anagram
    LeetCode 1348. Tweet Counts Per Frequency
    1349. Maximum Students Taking Exam(DP,状态压缩)
    LeetCode 1345. Jump Game IV(BFS)
    LeetCode 212. Word Search II
    LeetCode 188. Best Time to Buy and Sell Stock IV (动态规划)
    LeetCode 187. Repeated DNA Sequences(位运算,hash)
  • 原文地址:https://www.cnblogs.com/yangyangyang/p/6774330.html
Copyright © 2011-2022 走看看