美文网首页Swift学习记录
7、Swift 中的内存管理

7、Swift 中的内存管理

作者: Fred丶Lee | 来源:发表于2023-04-20 19:46 被阅读0次

Swift 是一种快速、安全、现代的编程语言,它具有自动引用计数(ARC)机制来管理内存。这个机制可以自动追踪和释放不再需要的内存,使得开发者不必手动处理内存分配和释放的问题。在这篇博客中,我们将介绍 Swift 中的内存管理机制,以及如何避免内存泄漏和野指针等问题。

ARC 简介
Swift 使用自动引用计数(ARC)机制来追踪并管理内存。每个类实例都有一个引用计数,当一个实例被引用时,它的引用计数将增加。当一个实例不再被引用时,它的引用计数将减少。当引用计数变为 0 时,实例的内存将被自动释放。

例如,下面的代码展示了如何创建一个类并实例化它:

class Person {
    var name: String
    
    init(name: String) {
        self.name = name
        print("\(name) is being initialized.")
    }
    
    deinit {
        print("\(name) is being deinitialized.")
    }
}

var person1: Person?
var person2: Person?
var person3: Person?

person1 = Person(name: "Alice")  // 输出 "Alice is being initialized."
person2 = person1
person3 = person1

person1 = nil
person2 = nil

// 输出 "Alice is being deinitialized."

在上面的例子中,我们创建了一个 Person 类,它有一个字符串类型的属性 name。我们实例化了三个 Person 对象,然后将 person1 和 person2 的引用都指向了第一个对象。这时,person1 和 person2 的引用计数都变成了 2。当我们将 person1 和 person2 的引用都置为 nil 时,引用计数减少到 0,Person 对象的内存就会被自动释放。

内存泄漏
内存泄漏是一种常见的问题,指的是在程序运行时,一些对象无法被回收并释放,从而导致内存占用不断增加,最终导致程序崩溃。在 Swift 中,内存泄漏通常是由于循环引用造成的。

循环引用指的是两个或多个对象之间互相持有对方的强引用,从而导致它们的引用计数永远不会变为 0,即使它们不再被使用。这时,内存就会一直被占用,从而导致内存泄漏。

例如,下面的代码展示了一个循环引用的例子:

class Person {
    var name: String
    var pet: Pet?
    
    init(name: String) {
        self.name = name
    print("\(name) is being initialized.")
}

deinit {
    print("\(name) is being deinitialized.")
}
class Pet {
var name: String
var owner: Person?

init(name: String) {
    self.name = name
    print("\(name) is being initialized.")
}

deinit {
    print("\(name) is being deinitialized.")
}

var person: Person?
var pet: Pet?

person = Person(name: "Alice")
pet = Pet(name: "Fluffy")

person?.pet = pet
pet?.owner = person

person = nil
pet = nil

// 输出 "Alice is being deinitialized."
// 输出 "Fluffy is being deinitialized."

swift
Copy code

在上面的例子中,我们创建了一个 Person 类和一个 Pet 类,它们之间相互持有对方的强引用。当我们将 personpet 的引用都置为 nil 时,它们的引用计数不会变为 0,因为它们互相持有对方的引用,从而导致内存泄漏。

为了避免循环引用和内存泄漏,我们可以使用弱引用和无主引用来打破引用循环。

  1. 弱引用和无主引用

弱引用是一种不会增加对象引用计数的引用,它通常用于解决循环引用的问题。在 Swift 中,我们可以使用 weak 关键字来声明一个弱引用。

例如,下面的代码展示了如何使用弱引用解决循环引用的问题:

class Person {
    var name: String
    var pet: Pet?
    
    init(name: String) {
        self.name = name
        print("\(name) is being initialized.")
    }
    
    deinit {
        print("\(name) is being deinitialized.")
    }
}

class Pet {
    var name: String
    weak var owner: Person?
    
    init(name: String) {
        self.name = name
        print("\(name) is being initialized.")
    }
    
    deinit {
        print("\(name) is being deinitialized.")
    }
}

var person: Person?
var pet: Pet?

person = Person(name: "Alice")
pet = Pet(name: "Fluffy")

person?.pet = pet
pet?.owner = person

person = nil
pet = nil

// 输出 "Alice is being deinitialized."
// 输出 "Fluffy is being deinitialized."

在上面的例子中,我们将 Pet 类的 owner 属性声明为一个弱引用,这样就不会增加 Person 对象的引用计数。当我们将 person 和 pet 的引用都置为 nil 时,它们的引用计数都变为 0,从而释放了内存。

另外,无主引用是一种类似于弱引用的引用,但是它假设引用的对象始终存在,不需要在对象释放时设置为 nil。在 Swift 中,我们可以使用 unowned 关键字来声明一个无主引用。

例如,下面的代码展示了如何使用无主引用解决循环引用的问题:

class Customer {
    var name: String
    var creditCard: CreditCard?
    
    init(name: String) {
        self.name = name
        print("\(name) is being initialized.")
    }
    
    deinit {
        print("\(name) is being deinitialized.")
    }
}

class CreditCard {
    let number: Int
    unowned let customer: Customer
    
    init(number: Int, customer: Customer) {
        self.number = number
        self.customer = customer
        print("Credit card #\(number) is being initialized.")
    }
    
    deinit {
        print("Credit card #\(number) is being deinitialized.")
    }
}

var customer: Customer?
customer = Customer(name: "Alice")

customer!.creditCard = CreditCard(number: 1234_5678_9012_3456, customer: customer!)

customer = nil

// 输出 "Alice is being deinitialized."
// 输出 "Credit card #1234567890123456 is being deinitialized."

在上面的例子中,我们将 CreditCard 类的 customer 属性声明为一个无主引用,这样就可以避免循环引用的问题。当我们将 customer 的引用置为 nil 时,它的引用计数变为 0,从而释放了内存。

总结
Swift 通过使用自动引用计数(ARC)来管理内存,我们只需要关注对象之间的引用关系即可。然而,当存在循环引用时,ARC 无法自动释放内存,可能导致内存泄漏。为了避免循环引用和内存泄漏,我们可以使用弱引用和无主引用来打破引用循环,从而释放内存。在编写 Swift 代码时,我们应该注意引用关系,避免出现循环引用和内存泄漏的情况。

相关文章

  • Swift--内存管理

    Swift内存管理概述 强引用循环 打破强引用循环 闭包中的强引用循环 Swift内存管理概述 Swift中的AR...

  • Swift 内存管理

    Swift 内存管理 [TOC] 前言 本文将介绍一下Swift中的内存管理,关于内存的一些基础知识可以参考我以前...

  • 十七、内存管理

    内存管理 跟OC一样,Swift也是采取基于引用计数的ARC内存管理方案(针对堆空间) Swift的ARC中有3中...

  • 每天学一点Swift----面向对象下(十)

    十九. Swift内存管理 1. Swift提供了强大的内存管理机制:Swift通过自动引用计数(ARC)可以很好...

  • 【Swift概念】Swift的内存管理

    Swift的内存管理怎么办?? 在Objective-C中无论ARC、MRC,开发中我们还是需要对内存进行管理,主...

  • Swift进阶06:内存管理 & Runtime

    本文主要介绍Swift中的内存管理,涉及引用计数、弱引用、强引用、循环引用、Runtime等 内存管理 - 强引用...

  • Swift中的内存管理

    一、内存分配   值类型,比如说枚举和结构体,它们的内存分配和管理都十分简单。当你新建一个值类型实例时,系统会自动...

  • Swift中的内存管理

    之前用Swift写了一个App,已经在App Store上架了。前两天更新了一些功能,然后用Instruments...

  • swift中的内存管理

    基于引用计数的ARC内存管理 循环引用 使用[weak ***]解决循环饮用 逃逸闭包 闭包的调用逃离了函数的作用域

  • Swift中的内存管理

    1、内存管理,weak和unowned2、@autoreleasepool3、C 指针内存管理 1、内存管理,we...

网友评论

    本文标题:7、Swift 中的内存管理

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