内存管理初级

一.内存分为五大区 :栈区,堆区,全局区,常量区,代码区
2.栈区特点:  
  •  系统分配,系统回收
  •  存储在栈区的数据为临时变量,即定义在方法体中的变量,包括形参.
  •  栈区的特点是 先进后出
3.堆区的特点
  •  人为地分配,人为地回收
  • 人为动态分配的空间,都是在堆区中开辟的
  • 标记删除
4.常量区的特点
  • 存储常量数据
  •  数据不可更改
5,全局区 特点
  •     在编译期,就存入到全局区
  •     只有等程序结束退出才释放
  •     全局变量只能被初始化一次 如果没有赋初始值,默认初始值为0
二.内存管理
   1.Manul Reference count  &  Auto Reference Count   (MRC &ARC)     referenceCount 引用计数 系统根据引用计数的个数来回收内存  
      要注意 引用计数 是为了管理内存 (1.防止出现野指针.  2.防止内存泄露)
   2.几个内存管理的要用到的方法:+ alloc  -retain  -release -copy -autorelease
     (1) +alloc (ReferenceCount)由0-1的过程
     (2) -retain  ( +1   返回地址  )   Person *person1=[person retain]; person 所指对象的引用计数加一
     (3)-release (-1    无返回值  )   [person1 release]; person1所指对象的引用计数减一
     (4)-copy  (本身引用计数不变,副本引用计数加一  返回新地址)  Person *p2=[p copy];p 所指对象的引用计数不变  p2所指对象的引用计数加一
     (5)-autorelease  在将来的某个时间将引用计数减一 注意 autorelease 之后 对系那个的 retainCount 不会马上减一 而是在将来某个时间减一 (这取决于他处于的 autoreleasepool什么时候释放).
  3.delloc   是由父类继承过来的类,有系统自动调用,当 对象 的引用计数值为0时,系统会自动调用 delloc (自己可以重写个 delloc 方法用于判断对象是否销毁);
      注意的一点是[super delloc]表示现在要调用从父类继承过来的 delloc 方法  (注意 :这一句话要放在方法体的最后边);
     在 dealloc 方法中要将所有 有retain属性 的实例变量 都 release   然后要使用[super dealloc];
  4. autoreleasepool 的工作原理  就像一个栈,哪个对象先被放进 pool ,哪个对象就最后 release (栈中存的是对象的地址,即这一块要释放的内存的地址)
     autoreleasepool  目前的建立方式是@ autoreleasepool{ }
      autoreleasepool中可以嵌套多个 autoreleasepool{}以便释放在程序中多次出现的有 autorelease 方法 的对象,避免内存空间不足,造成泄露.
   5.内存管理的原则:
     (1).引用计数的增加和减少相等,当引用计数降为0之后,不应该再使用这块内存
     (2).凡是使用(要理解为看到了,没有看到就不减)了 alloc,retain,或者 copy 让内存的引用计数增加了,就需要使用 release或者 autorelease 让内存的引用计数减少.在一段代码内,增加和减少的次数要相等.当引用计数值为0 时 ,对象所占的内存,就被系统回收
     (3).在一个{ }中referenceCount 的增加的次数要和减少的次数一样.有两个原因:
  •  1.是为了遵守内存管理原则. 
  •  2 有的必须要进行释放,因为比如在一个 if{ }的代码块中,如果没有 某些临时变量使用 alloc开辟了空间,那么出来 if{}代码块 这些临时变量就被系统销毁了,哪些创建的空间就会被 crash ,更为严重的时在 for 循环中开辟空间的时候.
       (4) 在一个{ }内如果有明显的出现了 alloc retain copy, 则一定要在这段代码结束之前 release.  要保证每一个{}中的+-平衡  .如果没有明显的出现,就不要用 release,比如便利构造器(它的释放 最好 是在自己的实现体中 autorelease  延迟释放 );
 
  6.copy 属性: 当一个类要使用 copy时, 生成自己的关于那个对象的副本 就一定要实现 NSCopying 协议  并且实现 NSCopying 协议中的 - copyWithZone:方法  .
     并且在这个方法中自己实现 copy 的细节   一般式要创建一个新的对象,将 self 的值赋给这个对象 然后返回这个对象的地址
    例:@interface Person:NSObject<NSCopying>
             ……..
        @end
        @implementation Person
          - (id)copyWithZone:(NSZone *)zone{

              Person *per=[[Person alloc]initWithName:self.name age:self.age gender:self.gender];
              return per;
            }
        @end


         person *p=[[Person alloc] initWithName:self.name age:self.age gender:self.gender];
         Person *p2=[p copy]; copy  内部的  alloc 不在内部释放   不然在外面看到  copy    会又释放一次
        注意:如果  没有实现 NSCopying 协议 而直接使用 copy 方法 就会引发crash   
                不是任何对象都可以接收 copy 消息只有接受了 NSCopying 协议的对象才能接收 copy 消息
    7. 关于浅拷贝 与 深拷贝  
       浅拷贝 与 深拷贝 根据自己的理解 其实并没有一个完整的定论.  
        一般的理解是 浅拷贝-----只是实现了”指针" 的拷贝  (内容共用,一个对象中内容的改变 会 导致另一个对象中内容的改变)
                              深拷贝—---至少有一层对象实现了产生对象的副本  (内容不共用, 一个对象中内容的改变,不会影响另一个对象)
                              完全拷贝———每一层都实现了对象的副本的产生(类中每一个实例变量都实现了深拷贝(每一层对象都是))
     其实 关于深拷贝 与浅拷贝 只是一个理解或者概念上的问题  不需要深究什么是深拷贝,什么是浅拷贝  他们只是几种拷贝方式

8.如果出现 两个对象相互引用的情况(如: husband 中存在 wife 对象 ,wife 中存在 husband 对象) 此时对象作为实例变量的属性的 attribute 的设置不应该两个对象同时都设置为 retain 或 copy,  否则会造成 retain Cycle ,导致两个对象都无法 dealloc .  解决办法是将一个类的实例变量设置为 assign 表示弱引用, 但这种方法要注意内存管理与野指针情况.
  同时要注意 代理委托的情况,当出现代理的情况的时候,代理的语义属性要设置为 assign 防止代理与其委托之间的循环引入,而导致无法释放
    最终一个设置语义属性的一个基本规则是:  属性的类型凡是没有带 * 都要设置为 assign (包括代理的 id 类型);
 我们常见的delegate往往是assign方式的属性而不是retain方式 的属性,赋值不会增加引用计数,就是为了防止delegation两端产生不必要的循环引用。如果一个UITableViewController 对象a通过retain获取了UITableView对象b的所有权,这个UITableView对象bdelegate又是a 如果这个delegateretain方式的,那基本上就没有机会释放这两个对象了。自己在设计使用delegate 模式时,也要注意这点
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值