• Objective-C 【内存管理&手动内存管理 综述】


    ———————————————————————————————————————————
    内存管理

    (1)Objective-C的内存管理



    栈区    存放局部变量(由于基本数据类型占用的存储空间是固定的,由系统去分配,我们不用去管,故栈区存放基本数据类型,)

    堆区    存放程序运行过程中动态分配的内存空间(对象类型是程序运行过程中动态分配的,他们的大小不固定。比如说是我们Person new申请来的,存放在堆区,也是我们需要管理的)

    ★所以内存管理的范围是   继承了NSObject的所有对象(堆区中的对象)
    ★这是为什么呢?因为代码执行完毕后,堆内存 不会自动释放(需要内存管理机制),而 栈内存 会自动释放(自动弹栈)

    引用计数器     (一般用%ld或者%tu去查看里面的值,无符号的)

    每个对象都有自己的引用计数器,它是一个整数表示对象被引用的次数,即现在有多少东西在使用这个对象,引用计数器的值变为0时,对象就销毁

    ①每一个对象刚生下来的时候,引用计数器都是1(对象一旦创建好,默认的引用计数器就是1)

    ②如果对象的引用计数器不为0,那么在整个程序的运行过程中,它占用的内存就不可能被回收(除非整个程序退出)

    ③当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1


    (2)Objective-C的内存管理分类

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

    ①Mannul Reference Counting(MRC,手动管理,在开发 iOS 4.1之前的版本项目时我们要自己负责使用引用计数来管理内存,比如手动retain、release、autorelease等。而在iOS之后的版本我们可以使用ARC,让系统自己管理内存)

    ②Automatic Reference Counting(ARC,自动引用计数,iOS 4.1后推出)

    ③Garbage Collection(垃圾回收,iOS不支持垃圾回收)

    ★苹果官方推荐我们使用ARC技术来管理内存,MRC理解就好


    ———————————————————————————————————————————
    手动内存管理(MRC)

    (1)首先我们要手动内存管理(MRC),就要先将自动管理关闭(关闭ARC)。

    关闭ARC的方法:

    点击项目(总的,蓝色)——> bulid setting ——> basic level ——>搜索 Objective-C Automatic Reference Counting ——> 此时会出现四个选项,全部设为 No 即可

    (2)我们判断对象是否需要回收,这是就要查看引用计数器的值,需要调用
    -(NSInteger)retainCount方法(这是一个有返回值的对象方法,返回值为NSInteger,NSInteger是一个动态类型,他的类型在不同的操作系统可能是int类型,也可能是long类型,他是有符号的。而NSUInerger是无符号类型,没有负数)

    retainCount的返回值  > 0   不会回收
    retainCount的返回值  = 0   回收内存空间

    ★注意:这里retainCount的返回值是 %tu 或者是 %ld 类型的~

    (3)回收对象内存空间的时候通常会自动调用一个方法,dealloc(释放对象的属性)

    我们可以通过重写dealloc这个方法来看看到底对象空间有没有被释放(再里面加一句话输出,如果释放了就会自动调用dealloc,那么这句话就会输出)

    ★★★这里注意重写dealloc和重写init不一样,要最后调用父类的dealloc方法,即最后调用 [super dealloc]; ,原因就是要先释放子类内存的再去释放父类的内存

    (4)有两个对象方法可以使对象的引用计数器的值增加1和减少1

    ①使用 release  可以使引用计数  -1
    ②使用 retain     可以使引用计数  +1

    (5)内存管理

    我们应该心里有这么一个观念,就是让对象的引用计数保持一个平衡的状态

    即:    retain + new = release  (增加引用计数=减少引用计数)


    代码:

    #import <Foundation/Foundation.h>

    @interface Person : NSObject
    -(void)run;
    @end

    #import "Person.h"

    @implementation Person
    - (void)dealloc
    {
        NSLog(@"对象内存空间释放!");
        [super dealloc];//这句话一定要放在重写dealloc方法的最后一句,意义是:先释放子类占用的内存空间,再释放父类占用的内存空间(和重写构造方法正好相反,初始化对象时是先执行父类的init,再执行子类的初始化)
    //    另外注意,永远不要直接调用dealloc方法,如果调用应该让retainCount = 0,但是如果你写 [p dealloc] 也是不会报错的,只是没有必要!这压根就是一个不需要你自己闲的蛋疼去写的一句话。
    }
    -(void)run
    {
        NSLog(@"run!");
    }
    @end

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Person *p=[Person new];
            
            NSLog(@"p->retainCount = %tu",[p retainCount]);
    //        这个地方因为创建了p,所以引用p的次数+1,所以输出的值为1。但是记住,这里必须将ARC关闭,如果不关闭是会报错的
            
            [p run];
            NSLog(@"p->retainCount = %tu",[p retainCount]);
    //        这里输出结果还是1,因为 [p run]; 只是调用了run方法,但是p被引用的次数还是1
            
            [p release];
    //        这里将引用计数-1,所以说此时引用计数为0,也就是此时将会自动调用dealloc方法,打印我们重写dealloc里面的“对象空间释放!”
             
            //        [p run];   //对象空间都释放了,但还是可以调用的,这是为什么呢?这个问题留在下节“单个对象的内存管理(野指针)去解释”            
       }
        return 0;
    }


    ———————————————————————————————————————————

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    Ceph rbd删除image遭遇watchers异常处理
    Ceph OSD更换硬盘后遭遇PG Inconsistent异常与处理
    Rook Ceph OSD异常,格式化osd硬盘重新挂载
    Count on an IEnumerable<dynamic>
    [原创] [C#] 转换Excel数字列号为字母列号
    [MAC] Load Crypto.Cipher.ARC4 Failed, Use Pure Python Instead.
    转:Chrome调试工具介绍
    转:一组jQuery插件的连接
    动态的链式传递执行
    C#中克隆随机数的三种方法(为什么我想到了茴字的四种写法
  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787886.html
Copyright © 2020-2023  润新知