5

我已阅读如何在 Xcode Instruments 中演示内存泄漏和僵尸对象?但这是针对objective-c的。这些步骤不适用。

通过阅读here,我了解到僵尸是以下对象:

  • 解除分配
  • 但是某些指针仍在尝试指向它们并向它们发送消息。

不完全确定这与访问已释放的对象有何不同。

我的意思是在 Swift 中你可以这样做:

var person : Person? = Person(name: "John")
person = nil
print(person!.name)

人被释放了吗?是的!

我们是否试图指出它?是的!

那么有人可以分享导致创建悬空指针的最常见错误吗?

4

4 回答 4

6

这是不到 15 行代码的僵尸攻击:

class Parent { }

class Child {
    unowned var parent: Parent // every child needs a parent

    init(parent: Parent) {
        self.parent = parent
    }
}

var parent: Parent? = Parent()
let child = Child(parent: parent!) // let's pretend the forced unwrap didn't happen
parent = nil // let's deallocate this bad parent
print(child.parent) // BOOM!!!, crash

这段代码中发生的情况是,它Child拥有一个对 的无主引用,一旦被释放Parent,它就会变得无效。Parent该引用包含一个指向不再存在的父级 (RIP) 的指针,访问该指针会导致崩溃并显示类似于以下内容的消息:

致命错误:尝试读取无主引用但对象 0x1018362d0 已被释放2018-10-29 20:18:39.423114+0200 MyApp [35825:611433] 致命错误:尝试读取无主引用但对象 0x1018362d0 已被释放

注意该代码在 Playground 中不起作用,您需要一个常规应用程序。

于 2018-10-29T18:22:56.627 回答
4

Zombie 对象Objective-C 对象,它们已被释放,但仍接收消息。

在 Objective-C 中,__unsafe_unretained可用于创建指向不增加引用计数的对象的附加指针。在 Swift 中,这将是unowned(unsafe).

这是一个独立的示例:

import Foundation

class MyClass: NSObject {
    func foo() { print("foo"); }

    deinit { print("deinit") }
}

unowned(unsafe) let obj2: MyClass
do {
    let obj1 = MyClass()
    obj2 = obj1
    print("exit scope")
}
obj2.foo()

obj1是指向新创建对象的指针,obj2也是指向同一对象的另一个指针,但不增加引用计数器。当do { ... }块离开时,对象被释放。通过发送消息给它obj2会导致僵尸错误:

exit scope
deinit
*** -[ZombieTest.MyClass retain]: message sent to deallocated instance 0x1005748d0

如果您使用Managed(例如,将指向 Swift 对象的指针转换为 Cvoid指针以便将它们传递给 C 回调函数)并且您没有选择正确的保留/未保留组合,也会发生这种情况。一个人为的例子是:

let obj2: MyClass
do {
    let obj1 = MyClass()
    obj2 = Unmanaged.passUnretained(obj1).takeRetainedValue()
    print("exit scope")
}
obj2.foo()
于 2021-07-29T14:01:27.767 回答
4

这不是悬空指针或僵尸。当您使用时,!您是在说“如果这是 nil,则崩溃”。您不应该将其person视为 Swift 中的指针。这是一个价值。该值可能是.some(T),也可能是.none(也称为nil)。这些都不是悬空的。它们只是两个不同的显式值。Swiftnil与其他语言中的空指针完全不同。当您明确要求它时,它只会像空指针一样崩溃。

要创建僵尸,您需要使用类似Unmanaged. 这在 Swift 中极为罕见。

于 2018-10-29T16:30:23.950 回答
1

Zombie Object是一个被释放的对象,它的行为就像活着一样。这是可能的,因为dangling pointer.

dangling pointer指向内存中数据不可预测的某个地址

  • Objective-C 有unsafe_unretained[About]属性。[例子]

  • 斯威夫特有

    • unowned(unsafe)[关于]参考
    • Unmanaged- non ARCObjc-代码的包装器
unowned(unsafe) let unsafeA: A

func main() {
    let a = A() // A(ref count = 1)
    unsafeA = a 
} // A(ref count = 0), deinit() is called

func additional() {
    unsafeA.foo() //<- unexpected
}
于 2021-12-02T13:44:02.070 回答