• Objective-C —内存管理(上)


    内存管理

    一、为什么要进行内存管理

    • 移动设备的内存极其有限,每个app所能占用的内存是有限制的

    • 下列行为都会增加一个app的内存占用
      创建一个OC对象
      定义一个变量
      调用一个函数或者方法

    • 内存占用多大
      当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等

      如果app占用内存过大,系统可能会强制关闭app, 造成闪退现象, 影响用户体验

    二、内存分类

    • 栈 :由编译器自动分配释放
    • 堆 :一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
    • 全局区(静态区):
      全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域
      未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
      程序结束释放
    • 常量区:另外还有一个专门放常量的地方, 程序结束释放
    • 代码区:存放二进制代码

    三、内存管理

    • 如何回收那些不需要再使用的对象?
      那就得学会OC的内存管理

    • 所谓内存管理, 就是对内存进行管理, 涉及的操作有:
      分配内存 : 比如创建一个对象, 会增加内存占用
      清除内存 : 比如销毁一个对象, 能减小内存占用

    • 内存管理的管理范围
      任何继承了NSObject的对象
      对其他非对象类型无效(int、char、float、double、struct、enum等 )

    • 只有OC对象才需要进行内存管理的本质原因
      OC对象存放于堆里面
      非OC对象一般放在栈里面(栈内存会被系统自动回收)

    四、堆和栈

    堆和栈的区别:(借用网上的一个很好的比喻)

    • 使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
    • 使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。 (经典!)

    代码示例

        int main(int argc, const char * argv[])
        {
           @autoreleasepool {
               int a = 10; // 栈
        
               int b = 20; // 栈
        
               // c : 栈
               // Car对象(计数器==1) : 堆
               
               Car *c = [[Car alloc] init];
           }
               // 经过上面的代码后, 栈里面的变量ac都会被回收
               // 但是堆里面的Car对象还会留在内存中, 因为它是计数器依然是1
               return 0;
        }
    

    五、引用计数器

    • 系统是如何判断 什么时候需要回收一个对象所占用的内存?
      根据对象的引用计数器
    5.1什么是引用计数器
    • 每个OC对象都有自己的引用计数器,由oc对象内部4个字节存储空间来存放
      它是一个整数
      从字面上, 可以理解为”对象被引用的次数”
      也可以理解为: 它表示有多少人正在用这个对象

      简单来说, 可以理解为: 引用计数器表示有多少人正在使用这个对象

    5.2根据引用计数器来确定是否回收对象
    • 当没有任何人使用这个对象时, 系统才会回收这个对象, 也就是说:
      当对象的引用计数器为0时, 对象占用的内存就会被系统回收
      如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序已经退出 )
      所以我们以后就是通过操作引用计数器来管理内存

    • 任何一个对象, 刚生下来的时候, 引用计数器都为1
      当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1

    5.3操作引用计数器

    要想管理对象占用的内存, 就得学会操作对象的引用计数器

    • 引用计数器的常见操作
      给对象发送一条retain消息, 可以使引用计数器值+1(retain方法返回对象本身)
      给对象发送一条release消息, 可以使引用计数器值-1
      给对象发送retainCount消息, 可以获得当前的引用计数器值

    需要注意的是: release并不代表销毁回收对象, 仅仅是计数器-1

    六、delloc方法

    • delloc方法调用
      当一个对象的引用计数器值为0时
      这个对象即将被销毁,其占用的内存被系统回收
      系统会自动给对象发送一条dealloc消息
      (因此, 从dealloc方法有没有被调用, 就可以判断出对象是否被销毁)

    • dealloc方法的重写
      一般会重写dealloc方法, 在这里释放相关资源, dealloc就是对象的遗言
      一旦重写了dealloc方法, 就必须调用[super dealloc],并且放在最后面调用

        - (void)dealloc
        {
           NSLog(@"Person ---- dealloc----");
      
           // 必须调用, 必须放在最后面
           [super dealloc];
        }
      
    • 使用注意
      不能直接调用dealloc方法
      一旦对象被回收了, 它占用的内存就不再可用, 坚持使用会导致程序崩溃(野指针错误)

    七、空指针、野指针

    • 僵尸对象
      已经被销毁的对象(不能再使用的对象)

    • 野指针
      指向僵尸对象(不可用内存/坏内存)的指针
      给野指针发消息会报EXC_BAD_ACCESS错误

    • 空指针
      没有指向存储空间的指针(里面存的是nil, 也就是0)
      给空指针发消息是没有任何反应的

    • 为了避免野指针错误的常见办法
      在对象被销毁之后, 将指向对象的指针变为空指针

    八Xocde设置

    要手动管理oc对象内存,需要在xcode中进行一下设置

    • 关闭ARC功能,才能手动调用retain、release等方法
    • 开启僵尸对象监控,默认情况下,Xcode是不会管僵尸对象的,使用一块被释放的内存也不会报错。为了方便调试,应该开启僵尸对象监控

    九、内存管理原则

    9.1 多对象内存管理

    • 单个对象的内存管理, 看起来非常简单

      如果对多个对象进行内存管理, 并且对象之间是有联系的, 那么管理就会变得比较复杂

      其实, 多个对象的管理思路 跟 很多游戏的房间管理差不多
      比如斗地主 QQ堂

    • 总的来说, 有这么几点管理规律
      只要还有人在用某个对象,那么这个对象就不会被回收
      只要你想用这个对象,就让对象的计数器+1
      当你不再使用这个对象时,就让对象的计数器-1

    9.2 内存管理原则

    • 苹果官方规定的内存管理原则
      谁创建谁release : 如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease

      谁retain谁release :只要你调用了retain,就必须调用一次release

    • 总结一下就是
      有加就有减
      曾经让对象的计数器+1,就必须在最后让对象计数器-1

    9.3 set方法的内存管理

    • set方法

        - (void)setCar:(Car *)car
        {
           if (car != _car)
           {
           // 对当前正在使用的车(旧车)做一次release
           [_car release];
           // 对新车做一次retain操作
       	_car = [car retain];
         }
       }
      

    9.4 dealloc方法的内存管理

    • dealloc方法

         - (void)dealloc
         {
            // 当人不在了,代表不用车了
            // 对车做一次release操作
            [_car release]; 
          [super dealloc];
         }
  • 相关阅读:
    JS的split函数用法
    JS中split用法和数组中元素的删除
    html模板
    jQuery实现AJAX
    JavaWeb学习笔记33--文件上传和下载
    JavaWeb学习笔记32--监听器(Listener)在开发中的应用
    JavaWeb学习笔记31--监听器(Listener)学习二
    JavaWeb学习笔记30--监听器(Listener)学习
    JavaWeb学习笔记29--Filter常见应用
    JavaWeb学习笔记28--Filter高级开发
  • 原文地址:https://www.cnblogs.com/xiaowenhui/p/4670203.html
Copyright © 2020-2023  润新知