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

inn6fuwd  于 2023-03-28  发布在  Swift
关注(0)|答案(4)|浏览(212)

我读过How to demonstrate memory leak and zombie objects in Xcode Instruments?,但那是针对objective-c的,步骤不适用。
通过阅读here,我了解到僵尸是这样的物体:

  • 解除分配
  • 但是指针仍然试图指向它们并向它们发送消息。

我不确定这和访问一个释放的对象有什么不同。
在Swift中,你可以:

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

人员是否已解除分配?是!
我们是要指出它吗?是的!
那么,有人能分享一下导致创建悬空指针的最常见错误吗?

jecbmhm3

jecbmhm31#

以下是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)的指针,访问该指针会导致崩溃,并显示类似于以下的消息:
致命错误:尝试读取无主引用,但对象0x 1018362 d 0已被deallocated 2018 -10-29 20:18:39.423114+0200 MyApp[35825:611433]致命错误:试图读取无主引用,但对象0x 1018362 d 0已被释放

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

rvpgvaaj

rvpgvaaj2#

当你使用!的时候,你是在说“如果这是nil,then crash.”你不应该把person看作Swift中的指针。它是一个值。这个值可能是.some(T),也可能是.none(也称为nil)。这两个都不是悬空的。它们只是两个不同的显式值。Swift的nil与其他语言中的空指针完全不同。只有当你明确要求它崩溃时,它才会像空指针一样崩溃。
要创建僵尸,你需要使用类似Unmanaged的东西。这在Swift中非常罕见。

93ze6v8z

93ze6v8z3#

Zombie objects是 *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发送消息会导致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()
pcrecxhr

pcrecxhr4#

Swift僵尸对象

Zombie Object是一个释放的对象(ref count为nil),它的行为本身就像是alive(接收消息)。这是可能的,因为dangling pointer
dangling pointer指向内存中数据不可预测的某个地址

  • Objective-C有unsafe_unretainedAbout(https://stackoverflow.com/a/66282129/4770877)属性。Example(https://stackoverflow.com/a/67576790/4770877)
  • 斯威夫特有
  • unowned(unsafe)About(https://stackoverflow.com/a/61020491/4770877)参考
  • Unmanaged-non ARC Objc的 Package 器-代码
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
}

相关问题