美文网首页
内存管理机制

内存管理机制

作者: wps_pro | 来源:发表于2018-03-30 10:52 被阅读0次

    内存管理机制

    Objective-C的内存管理主要有三种方式手动内存计数(MRC)、ARC(自动内存计数)、内存池。
    OC对象是放在堆内存中,这里的东西需要程序员手动管理;
    非OC对象是放在栈内存中,栈内存里的东西系统会自动管理。
    每个对象(特指:类的实例)内部都有一个retainCount的引用计数,

    使用alloc, new, copy或者mutableCopy等以及调用addObject等方法时,引用计数器+1,使用release时,引用计数器-1,当引用计数器为0时,对象被释放

    1) iOS内存管理的法则

    • 谁创建谁释放

    • 谁retain谁释放

    2)MRC手动管理内存(人工引用计数)

    当引用计数为0的时候,必须回收,引用计数不为0,不能回收,如果引用计数为0,但是没有回收,会造成内存泄露。如果引用计数为0,继续释放,会造成野指针。为了避免出现野指针,我们在释放的时候,会先让指针=nil。

    3)ARC自动管理内存(自动引用计数)

    在ARC模式下,只要没有强指针(强引用)指向对象,对象就会被释放。在ARC模式下,不允许使用retain、release、retainCount等方法。并且,如果使用dealloc方法时,不允许调用[super dealloc]方法。

    ARC模式下的property变量修饰词为strong、weak,相当于MRC模式下的retain、assign。strong:代替retain,缺省关键词,代表强引用。weak:代替assign,声明了一个可以自动设置nil的弱引用,但是比assign多一个功能,指针指向的地址被释放之后,指针本身也会自动被释放。

    4)内存池

    当我们不再使用一个对象的时候应该将其内存空间进行释放,有时候我们不知道何时应该将其释放。为了解决这个问题,OC提供了autorelease方法。
    autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作

    ARC的修饰符

    ARC主要提供了4种修饰符,他们分别是:__strong,__weak,__autoreleasing,__unsafe_unretained

    __strong

    表示引用为强引用。对应在定义property时的"strong"。所有对象只有当没有任何一个强引用指向时,才会被释放。
    注意:如果在声明引用时不加修饰符,那么默认是强引用。当需要释放强引用指向的对象时,需要将强引用置nil。

    __weak

    表示引用为弱引用。对应在定义property时用的weak。弱引用不会影响对象的释放,即只要对象没有任何强引用该指向,即使有100个弱引用对象指向也没用,该对象依然会被释放。在对象被释放的同时,指向它的弱引用会被自动置为nil,这个技术叫zeroing weak pointer。这样有效得防止无效指针、野指针的产生。__weak一般用在delegate关系中防止循环引用或者用来修饰指向由interface Buider编辑与生成的UI控件。

    __autoreleasing

    表示在autorelease pool中自动释放对象的引用,和MRC时代autorelease的用法相同。定义property时不能使用这个修饰符,任何一个对象的property都不应该是autorelease型的。
    一个常见的误解是,在ARC中没有autorelease,因为这样一个“自动释放”看起来好像有点多余。这个误解可能源自于将ARC的“自动”和autorelease“自动”的混淆。其实你只要看一下每个iOS App的main.m文件就能知道,autorelease不仅好好的存在着,并且变得更fashion了:不需要再手工被创建,也不需要再显式得调用[drain]方法释放内存池。

    __unsafe_unretained

    ARC是在iOS 5引入的,而这个修饰符主要是为了在ARC刚发布时兼容iOS 4以及版本更低的设备,因为这些版本的设备没有weak pointer system,简单的理解这个系统就是我们上面讲weak时提到的,能够在weak引用指向对象被释放后,把引用值自动设为nil的系统。这个修饰符在定义property时对应的是"unsafe_unretained",实际可以将它理解为MRC时代的assign:纯粹只是将引用指向对象,没有任何额外的操作,在指向对象被释放时依然原原本本地指向原来被释放的对象(所在的内存区域)。所以非常不安全。
    现在可以完全忽略掉这个修饰符了,因为iOS 4早已退出历史舞台很多年。

    内存泄露

    如果程序运行时一直分配内存而不及时释放无用的内存,会造成这样的后果:程序占用的内存越来越大,直至内存消耗殚尽,程序因无内存可用导致崩溃,这样的情况我们称之为内存泄漏。

    野指针

    已经被销毁的对象,称为僵尸对象,指向僵尸对象的指针,称之为野指针。

    如何避免内存泄露

    iOS提供了ARC功能,很大程度上简化了内存管理的代码。

    但使用ARC并不代表了不会发生内存泄露,使用不当照样会发生内存泄露。

    下面列举两种内存泄露的情况。

    1,循环参照

    A有个属性参照B,B有个属性参照A,如果都是strong参照的话,两个对象都无法释放。

    这种问题常发生于把delegate声明为strong属性了。

    例,

    @interface SampleViewController
    
    @property (nonatomic, strong) SampleClass *sampleClass;
    
    @end
    
    
    @interface SampleClass
    
    @property (nonatomic, strong) SampleViewController *delegate;
    
    @end
    
    

    上例中,解决办法是把SampleClass 的delegate属性的strong改为assing即可。

    2,死循环

    如果某个ViewController中有无限循环,也会导致即使ViewController对应的view关掉了,ViewController也不能被释放。

    这种问题常发生于animation处理。

    例,

    比如,

    CATransition *transition = [CATransition animation];
    
    transition.duration = 0.5;
    
    tansition.repeatCount = HUGE_VALL;
    
    [self.view.layer addAnimation:transition forKey:"myAnimation"];
    
    

    上例中,animation重复次数设成HUGE_VALL,一个很大的数值,基本上等于无限循环了。

    解决办法是,在ViewController关掉的时候,停止这个animation。

    -(void)viewWillDisappear:(BOOL)animated {
    
        [self.view.layer removeAllAnimations];
    
    }
    

    内存泄露的情况当然不止以上两种。

    即使用了ARC,我们也要深刻理解iOS的内存管理机制,这样才能有效避免内存泄露。

    相关文章

      网友评论

          本文标题:内存管理机制

          本文链接:https://www.haomeiwen.com/subject/eckmcftx.html