gpt4 book ai didi

Swift 类在作用域结束时取消初始化,而不是在上次使用后取消初始化

转载 作者:行者123 更新时间:2023-11-30 11:44:26 26 4
gpt4 key购买 nike

我问过this question询问局部变量中引用的生命周期的保证并被引用this thread其中讨论了类实例引用生命周期的确切语义。 AFAICT 从该线程来看,类实例可能会在最后一次使用包含最后一个引用的变量之后立即被取消初始化,甚至在评估同一语句中的其他表达式之前也是如此。有人认为,允许这种行为对于防止在写时复制数据结构中创建不必要的副本是必要的,我可以遵循这一点。

这引起了我的注意,到目前为止我从未见过 Swift 有这样的行为方式。每当我跟踪执行时,无论是在调试还是发布版本中,类实例仅在离开完整范围时才会初始化。

main() 的以下示例中,我创建了一个类的实例,该实例在其生命周期期间打印到控制台。请注意,在 main() 中调用 print() 期间或之后不会使用该实例:

public final class Something {
init() { print("Something.init()") }
deinit { print("Something.deinit") }
}

func main() {
let something = Something()
print("in main()")
}

main()

当使用调试或发布配置构建和运行此示例时,我看到以下执行顺序,即在 main( 中调用 print() 期间实例保持事件状态):

$ swift run -c release
Something.init()
in main()
Something.deinit

相反,我期望以下执行顺序:

$ swift run -c release
Something.init()
Something.deinit
in main()

我使用的是随 Xcode 9.2 一起发布的 Swift 编译器 4.0.3:

$ swift --version
Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2)
Target: x86_64-apple-macosx10.9

考虑到 Swift 编译器的开发人员正在尝试非常积极地减少 ARC 引用计数器(以及这种反初始化类实例)以避免写时复制中不必要的复制,如何解释这个执行顺序数据结构?这里是否还有其他一些优化在起作用,因为在这种情况下保持引用事件实际上并不会导致不必要的工作(只是内存分配的时间超过了严格必要的时间)?

我的问题不是要解决我遇到的特定问题,毕竟编译器正在创建完全符合语言允许范围的代码。我想很好地了解 Swift 编译器如何处理引用以及哪些优化在起作用,以便我可以衡量哪些代码模式在关键情况下可以带来良好的性能,例如当需要通过写时复制来复制大型数据结构时,或者涉及大量需要递增和递减的引用时。

最佳答案

我们来分析一下 Swift 在内存管理方面的工作原理:

  1. 当不再有对对象的强引用时,该对象将被释放
  2. 当声明变量的作用域结束时,变量将被“销毁”

鉴于上述两个事实,您的 Something 实例由 something 变量保持事件状态,该变量对其具有强引用,直到作用域结束,即直到main 函数返回。

尝试将 let Something = Something() 替换为 _ = Something(),您会看到您想要的预期行为:

Something.init()
Something.deinit
in main()

当持有实例的弱引用时,会发生相同的行为:weak var Something = Something()

请注意,something 变量和 Something 实例之间存在细微差别。该变量保存对实例的引用,而不是实例本身。因此,引用生命周期与变量生命周期相同,这就是影响实例生命周期的因素。为什么变量不尽快销毁,例如当编译器检测到不再需要它时,我不知道。

关于Swift 类在作用域结束时取消初始化,而不是在上次使用后取消初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48986455/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com