内存管理

现在iOS开发已经是arc(系统自动管理),不用自己release操作。

ios没有java那样的垃圾回收机制来管理内存,而是通过对象引用计数来管理内存的。

1 引用计数

 
 
ObjC采用引用计数(reference counting)的技术来进行管理:     1)每个对象都有一个关联的整数,称为引用计数器     2) 对象被创建时,则将对象的 引用计数加1;当使用该对象时,则将对象的引用计数加1     3)当结束使用该对象时,则将对象的引用计数减1     4)当引用计数的值变为0时,表示对象没有被使用,此时对象将被释放。
1.当对象被创建(通过alloc、new或copy等方法)时,其引用计数初始值为1
2.給对象发送retain消息,其引用计数加1
3.給对象发送release消息,其引用计数减1
4.給对象发送assign消息,只是赋值操作,其引用计数不受影响。
5.当对象引用计数归0时,ObjC給对象发送dealloc消息销毁对象
//创建cat对象,cat引用计数+1
Cat * cat = [Cat alloc]init];
//cat引用计数+1
[cat retain];
//cat引用计数-1
[cat release];
//cat引用计数-1
[cat release];
//cat引用计数==0,将cat对象指针置nil,否则会变成野指针。
cat = nil;

2 释放池(@autoreleasepool)

释放池(@ autoreleasepool)创建对象,区别是对象不会立刻释放,只有释放池释放后对象才会被释放。所以在释放池未释放的过程中,里面的对象任然存在。
使用自动释放池需要注意:
1.自动释放池实质上只是在释放的时候給池中所有对象对象发送release消息,不保证对象一定会销毁,如果自动释放池向对象发送release消息后对象的引用计数仍大于1,对象就无法销毁。

2.自动释放池中的对象会集中同一时间释放,如果操作需要生成的对象较多占用内存空间大,可以使用多个释放池来进行优化。比如在一个循环中需要创建大量的临时变量,可以创建内部的池子来降低内存占用峰值。

3.autorelease不会改变对象的引用计数

 
 
注意:   1)从MRC转换成ARC,可以更好地开发维护项目   2)如果工程引用了不支持ARC的库或者文件,可以在Build Phases的Compile Sources将对应的m文件的编译器参数配置为-fno-objc-arc   3)ARC能帮我们简化内存管理问题,但不代表它是万能的,还是有它不能处理的情况,这就需要我们自己手动处理,比如循环引用、非ObjC对象、Core Foundation中的malloc()或者free()等等
ARC提供四种修饰符,分别是__strong, __weak, __autoreleasing, __unsafe_unretained

__strong:强引用,持有所指向对象的所有权,无修饰符情况下的默认值。如需强制释放,可置nil。

NSTimer * timer = [NSTimer timerWith...];

相当于

  NSTimer * __strong timer = [NSTimer timerWith...];

当不需要使用时,强制销毁定时器

  [timer invalidate];
  timer = nil;
__weak:弱引用,不持有所指向对象的所有权,引用指向的对象内存被回收之后,引用本身会置nil,避免野指针。用于在block块语句以及代理防止循环引用。

比如避免循环引用的弱引用声明:

     __weak __typeof(self) weakSelf = self;
__autoreleasing:自动释放对象的引用,一般用于传递参数

_unsafe_unretained:__weak 一样唯一的区别便是,对象即使被销毁,指针也不会自动置空, 此时指针指向的是一个无用的野地址。如果使用此指针,程序会抛出 BAD_ACCESS 的异常 


循环中对象占用内存大
 
 
 for (int i = 0; i < 10000; i ++) {
     Person * soldier = [[Person alloc]init];
     [soldier fight];
 }
  该循环内产生大量的临时对象,直至循环结束才释放,可能导致内存泄漏,解决方法和上文中提到的自动释放池常见问题类似:在循环中创建自己的autoReleasePool,及时释放占用内存大的临时变量,减少内存占用峰值。
 for (int i = 0; i < 10000; i ++) {
     @autoreleasepool {
         Person * soldier = [[Person alloc]init];
         [soldier fight];
     }
 }
  
  
然而有时候autoReleasePool也不是万能的:
  例子:假如有2000张图片,每张1M左右,现在需要获取所有图片的尺寸,你会怎么做?
  如果这样做
 for (int i = 0; i < 2000; i ++) {
     CGSize size = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",i]].size;
     //add size to array
 }
  用imageNamed方法加载图片占用Cache的内存,autoReleasePool也不能释放,对此问题需要另外的解决方法,当然保险的当然是双管齐下了
 for (int i = 0; i < 2000; i ++) {
     @autoreleasepool {
         CGSize size = [UIImage imageWithContentsOfFile:filePath].size;
         //add siez to array
      }
 }



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值