IOS内存管理总结

IOS 内存管理模型

 

Objcective-C三种内存管理方式:

1:MRR (ManualRetain-Release): 手工持有-释放 方式

2  :  ARC(Automatic Reference Counting): 自动引用计数

3: GC (GarbageCollection) : 垃圾回收; 只适用于 MAC OS, 不能使用于 ios。

 

调试内存工具:

xcode自带的 Clang Static Ananlyzer. --- 编译期

  

            技术文章:TN2239,  IOS Debugging Magic (NSZombie来发现release 过多的对象)

 

            Instruments —— Viewing and Analyzing TraceData

 

内存管理策略:

            ios中对于内存管理是基于象所有维护, alloc , new, copy,mutableCopy头创建的象,那么这个对象就是拥有所有权。

            retain– 引用计数加 1

            release-引用计数减1

            直到为0, 就会触发 dealloc() 函数,该函数是由系统调用,我们不能调用;在该函数中要记住调用[super dealoc];

retain 方式是一种强引用方式, 为了避免父子对象间形成retain-cycle 现象:cocoa规定:父对象可以拥有子对象的强引用,而子对象只能拥有父对象的弱引用。

 

弱引用常见表现形式及注意事项:

            1:NotificationCenter,注意当不需要的时候,需要将消息的注销。

            2:delegate,当不需要需要将其设为空。

以免dealloc后,还在给其发送引发程序崩溃。

 

autorelease 和 release 区别:

            release:立即释放内存

            autorelease:不立即释放内存,那是在什么时候执行呢?

             每一个线程都至少有一个AutoreleasePool,管理着autorelease对象,相当于一个autorelease对象容

器,AutoreleasePool之间是一种“后进先出”方式的栈结构,当AutoreleasePool被dealloc的时候,

他就会去给容纳的每一个对象发送release消息为。  而系统什么时候调用AutoreleasePool的dealloc

呢?就是在调用其release 或 drain的时候(在ARC或MRR中,调用release,但是在Mac OS中

(或垃圾回收)中应该调用drain而不是 release, 垃圾回收中, release什么都不做)

 

为了理解AutoreleasePool是一个栈的形式,请参见一下代码:

– (id)findMatchingObject:(id)anObject {

                  id match = nil;

                  while (match == nil) {

                  NSAutoreleasePool*subPool = [[NSAutoreleasePool alloc] init];

                  NSError *error = nil;

                   NSString *fileContents = [[[NSString alloc]initWithContentsOfURL:url

                                                                        encoding:NSUTF8StringEncoding

                                                                        error:&error]autorelease];

                  [fileContents retain];

 

                  [subPooldrain];

         }

         return [match autorelease]; /* Let match go and return it. */

}

在函数的内部产生了一个subPool名字的autoreleasePool,他就进入了栈顶,然后subPool drain调用后,这个autoreleasePool就弹出了,这个池就销毁了,其间的fileContents如果没有在后面retain,那么也就会跟随subPool的销毁而销毁。通过调用retain,延长其生命期至栈的下一个AutoreleasePool。

 

如果drain的这个池不是栈顶,会怎么样?

如果你 drain 一个池,但是这个池却不在栈顶,那么栈内位于它上面的所有池就都 drain 了(这 意味着所有他们容纳的对象,都收到 release 消息)。如果你不小心忘记了调用一个池的 drain,那 么从嵌套结构上看,更外一层的池在 drain 的时候,会销毁这个池。ji

典型例子代码:

            1:release

            Person *per = [[Persion alloc]init];

            NSString *name = per.fullName;

            [per release];

2: autorelease

-(NSString*)fullName{

NSString *string = [[[NSString alloc]initWithFormat:@”%@”, self.lastname]autorelease];

return string;

}

允许其调用者来使用该对象。

3: 没有所有权,但是可以提供给调用者直接使用。

-(NSString*) fullName{

            NSString *string = [NSStringstringWithFormat:@”%@”, self.lastName”];

            return string;

    }

通过stringWithFormat返回的string没有所有权,方法调用者可以直接使用放回的数据

4:所有权不会通过函数返回而传递(这是我自己起的)。

            -(NSString*)fullName {

            NSString *string = [NSString alloc]initWithFormat:@”%@”, self.lastName];

            return string;

}         

导致内存泄漏,方法的调用者没有理由来release这个返回的string.

 

进程退出与dealloc 关系:

进程的内存会在退出时自动回收,当应用退出的时候,对象可能接收不到dealloc这样的消息。

不明白的地方:

            不能把资源管理的职能交给 dealloc,那么会暴露好多问题,比如:

         (我只能这样理解,对象与资源的生命周期时不一样的。所以不能放在对象的dealloc中处理,至于下面的问题,还需要再琢磨一下)

1. 对象图的拆除顺序问题

实际上,对象图的拆除是没有任何顺序保证的。也许你认为、你希望有一个具体明确 的顺序,但事实是没有。如果对象被放到了 autorelease 池,这个拆除的过程也会发生变化,并导致你无法预见的后果。

2. 系统稀缺资源不能回收

内存泄露问题,是系统的缺陷,应该被修正。但问题是通常这个问题不是立刻暴露出 来的。如果没有保留的时候,你认为某个资源已经释放,而实际上没有释放,你就会面临 更加严重的问题了。比如,如果文件句柄被用光了,其结果将是你无法保存数据。

3. 释放资源的操作由其他线程来做

如果对象在一个不确定的时刻被放到了 autorelease池中,它将被线程池中的线程来 dealloc。这对于有些只能供单一线程来访问的资源而言,是致命的错误。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值