iOS 知识点原理

问题:iOS 是如何管理内存的?

2020-05-13  本文已影响0人  姜小舟

引用计数(Reference Count)是一个简单而有效的管理对象生命周期的方式。不管是Objective-C、还是Swift,其内存管理方式都是基于引用计数的。

引用计数管理机制

引用计数可以有效地管理对象生命周期。当我们为一个指针创建一个新对象的时候,它的引用计数为1。当有一个新的指针指向这个对象的时候,我们将其引用计数加1,当某个指针不在指向这个对象时,我们将引用计数减1,当对象的引用计数变为0时,说明这个对象不在被任何指针指向了,这个时候我们就可以将对象销毁,回收内存。

在MRC的内存管理模式下,与对变量的管理相关的方法有:retain,release和autorelease。retain和release方法操作的是引用记数,当引用记数为零时,便自动释放内存。并且可以用NSAutoreleasePool对象,对加入自动释放池(autorelease 调用)的变量进行管理,当drain时回收内存。

我们在手动管理引用计数的时候,要明确地控制对象的生命周期,显式的调用每一个retain和release。我们必须清楚的了解每个接口对引用计数的处理(如把一个对象放到数组里引用计数会被+1,用alloc创建的对象的引用计数一开始就是1,用哪些接口创建的对象是已经被调用过autorelease的等等)。在处理引用计数时稍有疏忽,就可能导致程序崩溃或内存泄漏。

  • retain,该方法的作用是将内存数据的所有权附给另一指针变量,引用数加1,即retainCount+= 1;
  • release,该方法是释放指针变量对内存数据的所有权,引用数减1,即retainCount-= 1;
  • autorelease,该方法是将该对象内存的管理放到autoreleasepool中。
    //假设Number为预定义的类
Number* num = [[Number alloc] init];
Number* num2 = [num retain];         //此时引用记数+1,现为2
[num2 release];                      //num2 释放对内存数据的所有权 引用记数-1,现为1;
[num release];                       //num释放对内存数据的所有权 引用记数-1,现为0;
[num add:1 and 2];                   //bug,此时内存已释放。
//autoreleasepool 的使用 在MRC管理模式下,我们摒弃以前的用法,>NSAutoreleasePool对象的使用,新手段为@autoreleasepool
@autoreleasepool {
      Number* num = [[Number alloc] init];
      [num autorelease];            //由autoreleasepool来管理其内存的释放
}

这是苹果在 iOS5 中引入的内存管理机制. Objective-C 和 Swift 使用 ARC 追踪和管理应用的内存使用. ARC是编译器通过对代码的静态分析,确定对象的生命周期,并在合适的位置自动加上retain和release的机制。把内存管理交给编译器以后,我们不需要再调用任何的retain和release了。ARC减少了MRC带来的思考负担,减少了内存问题出现的可能性,也大幅减少了代码量,, 能够大幅度提升程序的 流畅性 和 可预测性 。

ARC的修饰符提供成员变量访问方法、权限、环境、内存管理类型的声明。
属性的参数分为三类,基本数据类型默认为(atomic,readwrite,assign),对象类型默认为(atomic,readwrite,strong),其中第三个参数就是该属性的内存管理方式修饰,修饰词可以是以下之一:

  • strong:强引用(引用计数+1),持有所指向对象的所有权,无修饰符情况下的默认值。如需强制释放,可置nil。
  • weak:弱引用,不持有所指向对象的所有权,引用指向的对象内存被回收之后,引用本身会置nil,避免野指针。
    使用set方法赋值时,实质上不保留新值,也不释放旧值,只设置新值。
  • retain:release旧值,再retain新值(引用计数+1)
    使用set方法赋值时,实质上是会先保留新值,再释放旧值,再设置新值,避免新旧值一样时导致对象被释放的的问题。
  • copy:release旧值,再copy新值(拷贝内容)
    一般用来修饰String、Dict、Array等需要保护其封装性的对象,尤其是在其内容可变的情况下,因此会拷贝(深拷贝)一份内容給属性使用,避免可能造成的对源内容进行改动。
    使用set方法赋值时,实质上是会先拷贝新值,再释放旧值,再设置新值。
    实际上,遵守NSCopying的对象都可以使用copy,当然,如果你确定是要共用同一份可变内容,你也可以使用strong或retain。
  • assign:直接赋值,一般用来修饰基本数据类型

ARC 使得内存管理更加轻松,但是 ARC 还有以下不足:

上一篇 下一篇

猜你喜欢

热点阅读