【问题标题】:what's the difference between access data in stack and heap? [duplicate]访问堆栈和堆中的数据有什么区别? [复制]
【发布时间】:2021-07-09 12:19:27
【问题描述】:

我有一个结构 Rectangle

struct Rectangle {
    var width: Float
    var length: Float
}

还有一个全局方法:

func add(p1: UnsafeMutablePointer<Float>, p2: UnsafeMutablePointer<Float>) -> Float {
    return p1.pointee + p2.pointee
}

rectangle 实例在堆栈中时,调用方法add 是安全的。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        var rectangle = Rectangle(width: 1.0, length: 2.0)
        let perimeter = add(p1: &rectangle.width, p2: &rectangle.length) * 2

    }
}

但是当rectangle实例在堆中时,调用方法add会崩溃。

class ViewController: UIViewController {
    var rectangle = Rectangle(width: 1.0, length: 2.0)
    override func viewDidLoad() {
        super.viewDidLoad()
        let perimeter = add(p1: &rectangle.width, p2: &rectangle.length) * 2

    }
}

崩溃信息如下:

Thread 1: Simultaneous accesses to 0x1038090d0, but modification requires exclusive access

【问题讨论】:

  • 据我所知,Swift 无法保证变量的位置。您不能确定属性是在堆中,还是局部变量在堆栈中。

标签: ios swift


【解决方案1】:

您正在观察 SE-0176: Enforce Exclusive Access to Memory 和 Swift 指南的 Memory Safety 章节的效果。这与堆栈或堆无关。

规则是:

不允许对同一个变量的两次访问重叠,除非两次访问都被读取

对于类属性和局部变量,您首先通过获取指向它的指针开始对rectangle 进行写访问(因为Rectangle 具有值语义,访问rectangle.width 也算作访问rectangle)并传递add 的第一个参数。此写访问将在add 返回时结束,但在结束之前,您通过获取指向rectangle.length 的指针开始了另一次写访问。

您可能想知道为什么“获取指向事物的指针”是 访问。这仅仅是因为你得到了 mutable 指针。如果你让add 使用不可变指针(或者只是常规的Float 参数),那么你就不会发生这种崩溃。

所以现在您看到了如何有重叠的写入访问,并且您的代码的两个 版本都没有遵循此规则。至于类属性和局部变量之间的区别,好吧,正如SE提案所说,在运行时检查类属性的独占内存访问:

类属性和全局变量必须动态执行规则。运行时可以跟踪正在进行的访问并报告任何冲突。

另一方面,对局部变量的访问虽然违反了规则,但实际上是安全的。根据 Swift 指南:

实际上,对结构属性的大多数访问可以重叠 安全。例如,如果上例中的变量 holly 是 改为局部变量而不是全局变量,编译器 可以证明对存储属性的重叠访问 结构是安全的:

func someFunction() {
    var oscar = Player(name: "Oscar", health: 10, energy: 10)
    balance(&oscar.health, &oscar.energy)  // OK
}

在上面的例子中,奥斯卡的健康和能量作为两者传递 输入输出参数到balance(_:_:)。编译器可以证明 内存安全被保留,因为这两个存储的属性不 以任何方式进行交互。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-10
    • 2016-08-18
    • 2016-01-19
    • 2020-10-24
    • 2015-01-15
    • 2011-11-20
    • 2014-07-13
    • 2021-08-29
    相关资源
    最近更新 更多