Swift ARC 自动引用计数

1、ARC

  • 引用类型在堆上的内存分配过程中有 8 字节的地址长度用来保存对象的引用计数,堆上的内存并不像栈上那样立即进行回收,系统会定时对堆上的内存进行检查,当某个实例不再被使用时,引用计数会变为 0,此时系统会自动释放实例所占用的内存空间,一旦释放就不能再访问这个实例的属性和方法。由于该过程是自动的,不需要开发人员来开辟和释放内存,因此称为自动引用计数,简称 ARC(Automatic Reference Counting)。

    • 为了避免使用中的实例被释放,ARC 会跟踪并计算每一个实例被多少属性、常量和变量所引用。
    • 引用有强引用和弱引用之分,这是为了保证在某些循环引用的情况下可以打破循环。
    • 为了保证实例在被属性、常量和变量引用时不会被意外释放,引用默认情况下会被设定为强引用。

1.1 ARC 示例

  • 在构造器和析构器中分别写一个打印语句,用来标示实例的创建和销毁。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class Student {

    var name: String
    var age: Int

    init(name: String, age: Int) {
    self.name = name
    self.age = age

    print("创建了一个实例")
    }

    deinit {

    print("销毁了一个实例")
    }
    }
  • 声明两个变量,把它们的类型声明为 Student 的可选型,现在它们还没有被赋值。

    1
    2
    var xiaoming: Student?
    var xiaogang: Student?
  • 通过构造器创建一个 Student 的实例,然后把这个实例赋值给第一个变量。

    1
    xiaoming = Student(name: "xiaoming", age: 12)
  • 此时运行程序输出如下。

    1
    创建了一个实例
  • 这次让第二个变量也引用这个实例,现在这个实例的引用计数为 2,代表着 Student 实例的内存地址被引用了两次。

    1
    xiaogang = xiaoming
  • 下面通过给变量赋值 nil 来断开引用,首先断开一个变量的引用,现在 Student 实例的引用计数已变为 1。

    1
    xiaogang = nil
  • 接着断开第二个变量的引用,现在没有任何属性或者变量引用这个实例了。

    1
    xiaoming = nil
  • 可以看到中控台打印信息如下,这个类调用了析构器,代表它被销毁了,释放出了实例所占用的内存空间。

    1
    销毁了一个实例
  • 看起来只是引用的数量增减那么简单,不过在真实的内存中,ARC 在检验某个对象的计数时不可避免的需要对堆内存进行加锁和解锁处理,也就是说无论你如何在代码层面优化代码,ARC 本身仍会带来一部分性能的损耗,这也解释了为什么值类型是更好的选择。

文章目录
  1. 1. 1、ARC
    1. 1.1. 1.1 ARC 示例
隐藏目录