Swift 4:Strings引用计数&如何计算

时间:2017-09-15 21:08:08

标签: swift string performance optimization reference-counting

此性能优化WWDC视频表明字符串是引用计数的,因为它们位于堆上。这对使用Strings的结构的性能以及Swift 4中是否有某些变化有影响(现在Strings又是集合 - 带有写入时的副本)。好奇如何证明这一点并获得实际计数。 CFGetRetainCount - 对字符串不起作用。

请参阅https://developer.apple.com/videos/play/wwdc2016/416/

enter image description here

使用Swift 4。

1 个答案:

答案 0 :(得分:3)

Swift Strings是没有引用计数的值类型。但是字符串包含的字符保存在引用类型容器存储中的堆中,并且具有引用计数。

这就是为什么Swift Strings具有写入优化的副本 - 就像其他集合一样 -

在Structs中使用字符串以及任何其他引用类型对性能来说并不是一个好主意,因为在每个Struct本身的赋值中,所有其他引用类型和字符串存储都会被保留。

如果您的值类型包含 N 引用类型,则在每个赋值/ deinit上都需要 N retain / release。并且您将获得值类型的复制开销。

但是如果你定义一个包含 N 引用类型的引用类型,那么在每个赋值/ deinit上你只有 1 保留/释放操作。

对于exp:

struct Label {
    var text: String
    var font: UIFont
    func draw() { }
}

let label1 = Label(text: "Hi", font: font)
let label2 = label1
retain(label2.text._storage)
retain(label2.font)
// finished using label1
release(label1.text._storage)
release(label1.font)
// finished using label2
release(label2.text._storage)
release(label2.font)

如果将Label作为一个类实现,则它将是

class Label {
        var text: String
        var font: UIFont
        func draw() { }
}

let label1 = Label(text: "Hi", font: font)
let label2 = label1
retain(label2)
// finished using label1
release(label1)
// finished using label2
release(label2)

另一方面,这种方法与Struct Philosophy的线程安全提议相冲突。所有副本都将共享相同的实例。

由于保留/释放操作在堆上并且必须是线程安全的,因此这些操作需要相当大的成本。

因此,如果你真的需要一个出色的性能,包括微优化,并且你想明智地使用值类型,你应该考虑这种方法。

PS:这种方法不会被Swift 4改变,写入时的复制是另一种优化。只有当包含具有多个引用的引用类型的值类型发生变异时,它才会创建副本。