Swift 4:是否对字符串引用计数以及如何获得该计数
Swift 4: Are Strings reference counted & how to get that count
这个性能优化 WWDC 视频表明字符串是引用计数的,因为它们在堆上。这会影响带有字符串的结构的性能以及 Swift 4 中是否发生了某些变化(现在字符串再次成为集合 - 写入时复制)。好奇如何证明这一点并获得实际计数。 CFGetRetainCount
- 不适用于字符串。
见https://developer.apple.com/videos/play/wwdc2016/416/
使用Swift 4.
Swift 字符串是没有引用计数的值类型。但是字符串包含的字符保存在一个引用类型容器存储的堆中,并且有引用计数。
这就是为什么 Swift 字符串具有写时复制优化 - 与其他集合一样 -
在 Structs 内部使用字符串 - 以及任何其他引用类型 - 对性能来说不是一个好主意,因为在 Struct 本身的每次分配中,所有其他引用类型和 String 存储都会保留。
当你有一个包含 N 引用类型的值类型时,在每个 assignment/deinit 上你需要 N retain/release.并且您将有值类型的复制开销。
但是如果你定义一个包含 N 个引用类型的引用类型,在每个 assignment/deinit 上你将只有 1 retain/release操作。
对于实验:
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 实现,它将是
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)
另一方面,这种方法与结构的线程安全提议相冲突。相同的实例将在所有副本之间共享。
由于 retain/release 操作在堆上并且它们必须是线程安全的,因此这些操作的成本相当高。
因此,如果您确实需要出色的性能(包括微优化),并且想要明智地使用值类型,则应该考虑这种方法。
PS:Swift没有改变这种做法 4、copy on write是另一个优化。只有当包含具有多个引用的引用类型的值类型发生变化时,它才会创建一个副本。
这个性能优化 WWDC 视频表明字符串是引用计数的,因为它们在堆上。这会影响带有字符串的结构的性能以及 Swift 4 中是否发生了某些变化(现在字符串再次成为集合 - 写入时复制)。好奇如何证明这一点并获得实际计数。 CFGetRetainCount
- 不适用于字符串。
见https://developer.apple.com/videos/play/wwdc2016/416/
使用Swift 4.
Swift 字符串是没有引用计数的值类型。但是字符串包含的字符保存在一个引用类型容器存储的堆中,并且有引用计数。
这就是为什么 Swift 字符串具有写时复制优化 - 与其他集合一样 -
在 Structs 内部使用字符串 - 以及任何其他引用类型 - 对性能来说不是一个好主意,因为在 Struct 本身的每次分配中,所有其他引用类型和 String 存储都会保留。
当你有一个包含 N 引用类型的值类型时,在每个 assignment/deinit 上你需要 N retain/release.并且您将有值类型的复制开销。
但是如果你定义一个包含 N 个引用类型的引用类型,在每个 assignment/deinit 上你将只有 1 retain/release操作。
对于实验:
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 实现,它将是
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)
另一方面,这种方法与结构的线程安全提议相冲突。相同的实例将在所有副本之间共享。
由于 retain/release 操作在堆上并且它们必须是线程安全的,因此这些操作的成本相当高。
因此,如果您确实需要出色的性能(包括微优化),并且想要明智地使用值类型,则应该考虑这种方法。
PS:Swift没有改变这种做法 4、copy on write是另一个优化。只有当包含具有多个引用的引用类型的值类型发生变化时,它才会创建一个副本。