如何在Swift中演示僵尸对象?

时间:2018-10-29 16:15:41

标签: swift memory-management nszombie dangling-pointer

我已经读过How to demonstrate memory leak and zombie objects in Xcode Instruments?,但这是针对目标c的。这些步骤不适用。

通过阅读here,我已经了解到僵尸是以下物体:

  • 已分配
  • 但是指针仍在尝试指向它们并向其发送消息。

不确定是否与访问已释放对象有什么不同。

我的意思是在Swift中您可以做到:

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

人被释放了吗?是的!

我们要指出吗?是的!

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

3 个答案:

答案 0 :(得分:3)

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

要创建僵尸,您需要使用Unmanaged之类的东西。这在Swift中非常罕见。

答案 1 :(得分:3)

以下15行代码中的僵尸攻击:

Child

此代码中发生的事情是Parent拥有对Parent的未拥有的引用,一旦释放了13:56:18,该引用将无效。该引用包含一个指向不再活动的父节点(RIP)的指针,并且该访问会导致崩溃,并显示类似以下消息:

  

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

注意:该代码无法在Playground中运行,为此您需要常规应用。

答案 2 :(得分:3)

Zombie objectsObjective-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 向它发送消息会导致 Zombie 错误:

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

如果您使用 Managed(例如到 convert pointers to Swift objects to C void pointers in order to pass them to C callback functions)并且没有选择正确的保留/未保留组合,也会发生这种情况。一个人为的例子是:

let obj2: MyClass
do {
    let obj1 = MyClass()
    obj2 = Unmanaged.passUnretained(obj1).takeRetainedValue()
    print("exit scope")
}
obj2.foo()